I'm trying to create a simple Image Viewer in Qt with zooming supported.
To display an image file I load it into a QImage and create a QPixmap.
class NN: public QWidget{
Q_OBJECT
Q_DISABLE_COPY(NN)
public:
NN(QWidget* parent = nullptr) : QWidget(parent){
}
const QPixmap& pixmap() const
{
return m_pixmap;
}
void setPixmap(const QPixmap& px)
{
m_pixmap = px;
update();
}
protected:
void paintEvent(QPaintEvent*)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, false);
style()->drawItemPixmap(&painter, rect(), Qt::AlignCenter, m_pixmap.scaled(rect().size()));
}
private:
QPixmap m_pixmap;
};
(This Widget is part of a ScrollArea)
This works fine, but when I try to load large images and zoom in, the performance starts to decrease (lag).
I thought of applying a clip to the drawItemPixmap() method, but I am not quite sure how and whether it would help increasing the performance.
My question is whether the clipping idea would work, and if so how. If not, maybe there is another way to gain performance?
When m_pixmap and/or rect() are very large, the bulk of your slowdown is likely coming from here:
m_pixmap.scaled(rect().size())
Here you are you are asking Qt to create a new QPixmap object the same size as rect(), which is a potentially very expensive operation; and passing that QPixmap object into the call to drawItemPixmap() which will draw just a small portion of the pixmap, after which the QPixmap object will get discarded, and the whole procedure will have to be done again the next time you want to redraw your object.
Needless to say, that can be very inefficient.
A more efficient approach would be to call QPainter::drawPixmap(const QRect & target, const Pixmap & pixmap, const QRect & source), like this:
painter.drawPixmap(rect(), m_pixmap, srcRect);
... and drawPixmap() will draw a scaled pixmap of size rect() (i.e. just the size of your widget) by rescaling the content of m_pixmap that is inside srcRect; much more efficient than rescaling the entire m_pixmap image.
You'll need to calculate the correct left/top/width/height values for srcRect, of course, but that should be straightforward with a little bit of algebra. (Basically just figure out what portion of the pixmap should currently be visible based on your widget's current zoom/pan state)
As I pointed out in this answer, it is better to use QGraphicsView for image scaling so I will translate the code to C++:
#include <QtWidgets>
class ImageViewer: public QGraphicsView{
public:
ImageViewer(QWidget *parent=nullptr):QGraphicsView(parent){
setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
// setAlignment(Qt::AlignLeft | Qt::AlignTop);
setAlignment(Qt::AlignCenter);
setBackgroundRole(QPalette::Dark);
QGraphicsScene *scene = new QGraphicsScene(this);
setScene(scene);
pixmapItem = new QGraphicsPixmapItem;
scene->addItem(pixmapItem);
}
bool setPixmap(const QPixmap & pixmap){
if(pixmap.isNull())
return false;
pixmapItem->setPixmap(pixmap);
return true;
}
void zoom(qreal f){
scale(f, f);
}
void zoomIn(){
zoom(factor);
}
void zoomOut(){
zoom(1.0 / factor);
}
void resetZoom(){
resetTransform();
}
void fitToWindow(){
fitInView(sceneRect(), Qt::KeepAspectRatio);
}
private:
qreal factor = 2.0;
QGraphicsPixmapItem * pixmapItem;
};
class MainWindow: public QMainWindow{
Q_OBJECT
public:
MainWindow(QWidget *parent=nullptr):QMainWindow(parent),
view(new ImageViewer)
{
setCentralWidget(view);
createActions();
createMenus();
resize(640, 480);
}
private Q_SLOTS:
void open(){
QStringList l;
for(const QByteArray & ba: QImageReader::supportedImageFormats()){
l << ("*." + QString::fromUtf8(ba));
}
QString filter = QString("Image Files(%1)").arg(l.join(" "));
QString fileName = QFileDialog::getOpenFileName(
this,
tr("Open Image"),
QDir::currentPath(),
filter
);
if(!fileMenu->isEmpty()){
bool loaded = view->setPixmap(QPixmap(fileName));
fitToWindowAct->setEnabled(loaded);
updateActions();
}
}
void fitToWindow(){
if(fitToWindowAct->isChecked())
view->fitToWindow();
else
view->resetZoom();
updateActions();
}
void about(){
QMessageBox::about(this, "ImageViewer", "ImageViewer");
}
private:
void createActions(){
openAct = new QAction("&Open...", this);
openAct->setShortcut(QKeySequence("Ctrl+O"));
connect(openAct, &QAction::triggered, this, &MainWindow::open);
exitAct = new QAction("E&xit", this);
exitAct->setShortcut(QKeySequence("Ctrl+Q"));
connect(exitAct, &QAction::triggered, this, &MainWindow::close);
zoomInAct = new QAction(tr("Zoom &In (25%)"), this);
zoomInAct->setShortcut(QKeySequence("Ctrl++"));
zoomInAct->setEnabled(false);
connect(zoomInAct, &QAction::triggered, view, &ImageViewer::zoomIn);
zoomOutAct = new QAction(tr("Zoom &Out (25%)"), this);
zoomOutAct->setShortcut(QKeySequence("Ctrl+-"));
zoomOutAct->setEnabled(false);
connect(zoomOutAct, &QAction::triggered, view, &ImageViewer::zoomOut);
normalSizeAct = new QAction(tr("&Normal Size"), this);
normalSizeAct->setShortcut(QKeySequence("Ctrl+S"));
normalSizeAct->setEnabled(false);
connect(normalSizeAct, &QAction::triggered, view, &ImageViewer::resetZoom);
fitToWindowAct = new QAction(tr("&Fit to Window"), this);
fitToWindowAct->setShortcut(QKeySequence("Ctrl+F"));
fitToWindowAct->setEnabled(false);
fitToWindowAct->setCheckable(true);
connect(fitToWindowAct, &QAction::triggered, this, &MainWindow::fitToWindow);
aboutAct = new QAction(tr("&About"), this);
connect(aboutAct, &QAction::triggered, this, &MainWindow::about);
aboutQtAct = new QAction(tr("About &Qt"), this);
connect(aboutQtAct, &QAction::triggered, qApp, &QApplication::aboutQt);
}
void createMenus(){
fileMenu = new QMenu(tr("&File"), this);
fileMenu->addAction(openAct);
fileMenu->addSeparator();
fileMenu->addAction(exitAct);
viewMenu = new QMenu(tr("&View"), this);
viewMenu->addAction(zoomInAct);
viewMenu->addAction(zoomOutAct);
viewMenu->addAction(normalSizeAct);
viewMenu->addSeparator();
viewMenu->addAction(fitToWindowAct);
helpMenu = new QMenu(tr("&Help"), this);
helpMenu->addAction(aboutAct);
helpMenu->addAction(aboutQtAct);
menuBar()->addMenu(fileMenu);
menuBar()->addMenu(viewMenu);
menuBar()->addMenu(helpMenu);
}
void updateActions(){
zoomInAct->setEnabled(not fitToWindowAct->isChecked());
zoomOutAct->setEnabled(not fitToWindowAct->isChecked());
normalSizeAct->setEnabled(not fitToWindowAct->isChecked());
}
ImageViewer *view;
QAction *openAct;
QAction *exitAct;
QAction *zoomInAct;
QAction *zoomOutAct;
QAction *normalSizeAct;
QAction *fitToWindowAct;
QAction *aboutAct;
QAction *aboutQtAct;
QMenu *fileMenu;
QMenu *viewMenu;
QMenu *helpMenu;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
#include "main.moc"
Related
I try to create a green circle which every 5 seconds disappears.
Actually, I have the green circle created with the QPainter method. I tried QTimer and others methods but I can't find the good solution.
I overrided the paintEvent function like this :
void MainWindow::paintEvent(QPaintEvent *)
{
QPainter painter(this);
Qt::BrushStyle style = Qt::SolidPattern;
QBrush brush(Qt::green, style);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(brush);
painter.drawEllipse(525, 5, 50, 50);
}
MainWindow::MainWindow() : QWidget()
{
QTimer *ledtimer = new QTimer(this);
connect(ledtimer, SIGNAL(timeout()), this, SLOT(run_led()));
ledtimer->start(5000);
}
I tried to do something like this, but when i'm using run_led, it tells that painter is already removed (i tried in MainWindow class).
I understand the signal function and the timer, I used it in another files, so some tips would be appreciated. Am I supposed to use timers to make circles wink ?
Define a flag boolean that changes every 5 seconds and in paint use a brush as global variable
void MainWindow::paintEvent(QPaintEvent *)
{
....
QBrush brush(myBrush, style);
...
}
and in slot (run_led)
void MainWindow::run_led()
{
c != true;
if(c)
{
myBrush=Qt::green;
}
else
{
myBrush=Qt::gray;
}
}
Assuming your MainWindowinherits QMainWindow
MainWindow::paintEvent(QPaintEvent *) is a function that tells the systems to render your window.
So I let you guess what goes wrong when you override it like this.
But you can put the drawing in a QWidget made for this : QGraphicsView which displays the content of QGraphicsScene .
You should create a slot to do what you want, like this :
void MainWindow::on_led_timer_timeout(){
/*
Do stuff the the QGraphicsScene or QGraphicsView
*/
}
And then connect the correct signal of your QTimer to it :
connect(ledtimer, &QTimer::timeout, this, &MainWindow::on_led_timer_timeout);
class QSimpleLed : public QWidget
{
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor)
public:
using QWidget::QWidget;
void setColor(const QColor& c) {
if (m_color != m) {
m_color = m;
update();
}
}
QColor color() const;
void paintEvent(QPaintEvent *) override;
private:
QColor m_color;
}
Implementation above should be obvious.
int main(int argc, char* argv[])
{
QApplication app{argc, argv};
QSimpleLed led;
auto animation = new QPropertyAnimation(&led, "color");
animation->setStartValue(Qt::red);
animation->setEndValue(Qt::green);
animation->setLoopCount(-1);
animation->setDuration(5000);
animation->start();
led.show();
return app.exec();
}
I am animating a QGraphicsTextItem that I have added a frame around. During the animation the text seems to shake slightly inside the frame, which is very annoying.
An example code:
class MovingFrameText : public QGraphicsTextItem
{
Q_OBJECT;
public:
MovingFrameText( ) : QGraphicsTextItem(0)
{
setPlainText ( "human ");
QFont f = font();
f.setPixelSize(40);
setFont(f);
setFlags(QGraphicsItem::ItemIsMovable);
}
QRectF boundingRect() const
{
return QGraphicsTextItem::boundingRect().adjusted(-2,-2,+2,+2);
}
void paint(QPainter *painter,const QStyleOptionGraphicsItem *option,QWidget *widget)
{
QGraphicsTextItem::paint(painter,option,widget);
painter->setPen(Qt::black);
painter->drawRect(boundingRect());
}
};
int main(int argc, char *argv[])
{
QApplication app(argc,argv);
MovingFrameText t;
t.setPos(640,680);
QGraphicsScene scene;
scene.addItem(&t);
QGraphicsView view(&scene);
view.resize(640, 680);
view.show();
auto moveAnimation = new QPropertyAnimation( &t, "pos" );
moveAnimation->setDuration( 10000 );
moveAnimation->setStartValue( QPointF(640, 680) );
moveAnimation->setEndValue( QPointF(0, 0) );
moveAnimation->setEasingCurve( QEasingCurve::Linear );
moveAnimation->start(QAbstractAnimation::DeleteWhenStopped);
return app.exec();
}
Is there any way to smooth the animation?
Solution
You can substantially improve the animation by:
Using QVariantAnimation instead of QPropertyAnimation and calling QGraphicsItem::update on each iteration
Buffering the painting using an additional QPainter with a QPixmap as a canvas for all painting operations and then painting the canvas using the painter passed to the paint method
Note: The QGraphicsTextItem will still shake a bit, but at least it will behave as one object instead of several independent ones.
Example
Here is an example I have prepared for you of how your code could be changed in order to implement the proposed solution:
class MovingFrameText : public QGraphicsTextItem
{
public:
MovingFrameText(const QString &text, QGraphicsItem *parent = nullptr)
: QGraphicsTextItem(parent)
{
QFont f(font());
f.setPixelSize(40);
setFont(f);
setPlainText(text);
}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->setClipping(true);
painter->setClipRect(option->rect);
painter->setRenderHint(QPainter::SmoothPixmapTransform);
QPixmap canvas(option->rect.size());
QPainter canvasPainter;
canvas.fill(Qt::transparent);
canvasPainter.begin(&canvas);
canvasPainter.setFont(font());
canvasPainter.drawRect(option->rect.adjusted(0, 0, -1, -1));
canvasPainter.drawText(option->rect, toPlainText());
painter->drawPixmap(0, 0, canvas);
}
};
int main(int argc, char *argv[])
{
QApplication app(argc,argv);
QGraphicsView view;
auto *t = new MovingFrameText("human");
view.setScene(new QGraphicsScene(&view));
view.setAlignment(Qt::AlignLeft | Qt::AlignTop);
view.setSceneRect(0, 0, 640, 680);
view.scene()->addItem(t);
view.show();
auto *moveAnimation = new QVariantAnimation();
moveAnimation->setDuration(10000);
moveAnimation->setStartValue(QPointF(640, 680));
moveAnimation->setEndValue(QPointF(0, 0));
moveAnimation->start(QAbstractAnimation::DeleteWhenStopped);
QObject::connect(moveAnimation, &QVariantAnimation::valueChanged, [t](const QVariant &value){
t->setPos(value.toPointF());
t->update();
});
return app.exec();
}
#scopchanov answer is a very good one. I added here a solution I tested as well, and seems to work. I will need further time to inspect which one I think is better, but I will leave it here for others to try, if you end with a similar issue.
class MovingFrameText : public QGraphicsTextItem
{
Q_PROPERTY( QPointF pos READ pos WRITE setPosition )
public:
void setPosition(QPointF pos)
{
setPos(floor(pos.x()+0.5),floor(pos.y()+.5) );
}
};
I try to create a simple application with QGraphicsView. The application can load graphical files with different ratios in the view. I would like to implement the following feature: on the application window resize, the content of the view should be also resized and centered. I do not know this part of the Qt well, so I can resize the content, but I cannot center it. How can I fix it?
MainWindow.h snippet:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
void resizeEvent(QResizeEvent *event) override;
public slots:
void onButtonClicked();
private:
bool m_flag = false;
QGraphicsPixmapItem *m_item = nullptr;
QGraphicsView *m_view = nullptr;
QPixmap m_pixmap;
};
MainWindow.cpp:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
auto central = new QWidget(this);
setCentralWidget(central);
// layouts
auto mainLayout = new QVBoxLayout;
mainLayout->setAlignment(Qt::AlignTop);
central->setLayout(mainLayout);
// top layout
auto topLayout = new QHBoxLayout;
topLayout->setAlignment(Qt::AlignLeft);
mainLayout->addLayout(topLayout);
auto btn = new QPushButton(this);
btn->setText("Test");
connect(btn, &QPushButton::clicked, this, &MainWindow::onButtonClicked);
topLayout->addWidget(btn);
m_view = new QGraphicsView;
mainLayout->addWidget(m_view);
auto scene = new QGraphicsScene;
m_view->setScene(scene);
m_view->setMinimumSize(800, 600);
m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
QString name = ":/pic1.jpg";
m_pixmap = QPixmap{ name }.scaled(800, 600, Qt::KeepAspectRatio);
m_item = scene->addPixmap(m_pixmap);
m_view->viewport()->resize(m_pixmap.size());
}
void MainWindow::onButtonClicked()
{
m_flag = !m_flag;
QString name = m_flag ? ":/pic2.png" : ":/pic1.jpg";
m_pixmap = QPixmap{ name }.scaled(m_view->size(), Qt::KeepAspectRatio);
m_item->setPixmap(m_pixmap);
m_view->fitInView(m_item, Qt::KeepAspectRatio);
}
void MainWindow::resizeEvent(QResizeEvent *event)
{
QMainWindow::resizeEvent(event);
m_view->fitInView(m_item, Qt::KeepAspectRatio);
}
Test result for the pic2.png:
When an image is scaled, it is done with respect to the top left, so it will always look up if the height is smaller than the prefix or to the right if the width is smaller.
The solution is to repaint the scaled QPixmap in the middle of the final QPixmap.
const QSize pixmap_size{800, 600};
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
auto central = new QWidget(this);
setCentralWidget(central);
// layouts
auto mainLayout = new QVBoxLayout;
mainLayout->setAlignment(Qt::AlignTop);
central->setLayout(mainLayout);
// top layout
auto topLayout = new QHBoxLayout;
topLayout->setAlignment(Qt::AlignLeft);
mainLayout->addLayout(topLayout);
auto btn = new QPushButton(this);
btn->setText("Test");
connect(btn, &QPushButton::clicked, this, &MainWindow::onButtonClicked);
topLayout->addWidget(btn);
m_view = new QGraphicsView;
mainLayout->addWidget(m_view);
auto scene = new QGraphicsScene;
m_view->setScene(scene);
m_view->setMinimumSize(pixmap_size);
m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_pixmap = QPixmap(pixmap_size);
m_pixmap.fill(Qt::transparent);
m_item = new QGraphicsPixmapItem;
m_view->scene()->addItem(m_item);
show();
onButtonClicked();
}
QPixmap MainWindow::createPixmap(const QString & filename, const QSize & size) const{
QPixmap tmp = QPixmap{ filename }.scaled(size, Qt::KeepAspectRatio);
QPixmap pixmap(size);
pixmap.fill(Qt::transparent);
QPainter p(&pixmap);
QPoint point(QRect({}, size).center()-tmp.rect().center());
p.drawPixmap(point, tmp);
p.end();
return pixmap;
}
void MainWindow::onButtonClicked()
{
QString name = m_flag ? ":/pic2.png" : ":/pic1.jpg";
m_item->setPixmap(createPixmap(name, pixmap_size));
m_flag = !m_flag;
m_view->fitInView(m_item, Qt::KeepAspectRatio);
}
void MainWindow::resizeEvent(QResizeEvent *event)
{
QMainWindow::resizeEvent(event);
m_view->fitInView(m_item, Qt::KeepAspectRatio);
}
I'm trying to draw on QLabel in Qt like this:
paintscene.h:
class PaintScene : public QWidget
{
Q_OBJECT
public:
PaintScene(QWidget* parent = NULL);
QVector<QLabel*> _layers;
QColor _color;
int _width;
void mousePressEvent(QMouseEvent* event);
private slots:
void updateWidth();
};
paintscene.cpp:
PaintScene::PaintScene(QWidget* parent) : QWidget(parent)
{
_width = 10;
_color = Qt::red;
QLabel* inital = new QLabel(this);
inital->setStyleSheet("QLabel { background-color : white; }");
_layers.push_back(inital);
QGridLayout* layout = new QGridLayout();
layout->addWidget(inital, 1, 1, 1, 1);
this->setLayout(layout);
}
void PaintScene::mousePressEvent(QMouseEvent *event)
{
QImage tmp = _layers.back()->pixmap()->toImage();
QPainter painter(&tmp);
QPen paintpen(_color);
paintpen.setWidth(_width);
painter.setPen(paintpen);
painter.drawPoint(event->x(), event->y());
_layers.back()->setPixmap(QPixmap::fromImage(tmp));
}
The list is needed because I want to implement the work with layers (QLabel - a separate layer).
However, I get an error, the program terminates. The error occurs on the line QImage tmp = _layers.back()->pixmap()->toImage();.
What makes this happen? How can this be fixed? Maybe for a layer to use something different, not QLabel?
#Jeremy Friesner is right about the reason for the error, not having a QPixmap this will be null, in my answer I will show a possible solution
void PaintScene::mousePressEvent(QMouseEvent *event)
{
QLabel *label = _layers.back();
const QPixmap *pix= label->pixmap();
QPixmap pixmap;
if(pix)
pixmap = *pix;
else{
pixmap = QPixmap(label->size());
pixmap.fill(Qt::transparent);
}
QPainter painter(&pixmap);
QPen paintpen(_color);
paintpen.setWidth(_width);
painter.setPen(paintpen);
painter.drawPoint(event->pos());
painter.end();
label->setPixmap(pixmap);
}
From the Qt docs for QLabel::pixmap():
This property holds the label's pixmap
If no pixmap has been set this will return 0.
... so when you do this:
QImage tmp = _layers.back()->pixmap()->toImage();
pixmap() is returning NULL (because the QLabel has never had any QPixmap set on it yet), and then you try to dereference that NULL pointer to call toImage() on it, hence the crash.
To avoid crashing, don't try to create a QImage from a NULL QPixmap pointer.
I suspect you wanted to be calling grab() instead of pixmap() -- grab() will create a QPixmap for you that contains the visual appearance of the QLabel. However, an even better approach would be to avoid messing about with QPixmaps at all; instead, make your own subclass of the QLabel class, and override its paintEvent(QPaintEvent *) method to first call up to QLabel::paintEvent(e) and then use a QPainter to draw the additional point afterwards. That will be easier to implement and also more efficient at runtime.
I have a problem regarding a QWidget (custom made) inside a QMainWindow (custom made). My problem is that when I add my widget to my window as its central widget using setCentralWidget() method, it won't show the widgets background. It's important to show the background correctly.
Here is my MyWindow.cpp code:
#include "MyMainWindow.h"
MyMainWindow::MyMainWindow(QWidget * parent, Qt::WindowFlags flag) :
QMainWindow(parent, flag)
{
this->setFixedSize(1120, 630);
menu = new MyMenu(this);
// setting = new MySetting();
// tutorial = new MyTutorial();
// game = new MyGame();
this->setCentralWidget(menu);
this->show();
}
MyMainWindow::~MyMainWindow()
{
}
My MyMenu.cpp code:
#include "MyMenu.h"
MyMenu::MyMenu(QWidget *parent, Qt::WindowFlags f) :
QWidget(parent, f)
{
this->resize(1120, 630);
this->set_background();
this->construct_buttons();
this->construct_menu();
}
MyMenu::~MyMenu()
{
delete start;
delete setting;
delete tutorial;
delete exit;
delete buttons;
delete logo;
delete menu;
}
void MyMenu::construct_menu()
{
menu = new QVBoxLayout(this);
logo = new QLabel(this);
QPixmap *pixmap = new QPixmap("/home/kahrabian/ClionProjects/Shooter-AP93UT/Contents/logo.png");
logo->setPixmap(*pixmap);
logo->setAlignment(Qt::AlignHCenter);
menu->addWidget(logo);
menu->addLayout(buttons);
delete pixmap;
}
void MyMenu::construct_buttons()
{
buttons = new QHBoxLayout();
start = new QPushButton("Start", this);
buttons->addWidget(start);
setting = new QPushButton("Setting", this);
buttons->addWidget(setting);
tutorial = new QPushButton("Tutorial", this);
buttons->addWidget(tutorial);
exit = new QPushButton("Exit", this);
buttons->addWidget(exit);
}
void MyMenu::set_background()
{
QPalette *palette = new QPalette();
palette->setBrush(this->backgroundRole(),QBrush(QImage("/home/kahrabian/ClionProjects/Shooter-AP93UT/Contents/background_menu.jpg")));
this->setPalette(*palette);
delete palette;
}
My main.cpp code:
#include <QApplication>
#include "MyMenu.h"
#include "MyMainWindow.h"
int main(int argc, char **argv)
{
QApplication app (argc, argv);
MyMainWindow *mainwin = new MyMainWindow();
// MyMenu *MyMenu = new MyMenu();
// MyMenu->show();
return app.exec();
}
Can anyone help me with this problem??
Check this answer.
I would recommend you to use Qt style sheets.
You would need to call something like this:
setStyleSheet("image: url(path/to/background/image.png);");
on your widget.
Also, you might need to implement paintEvent() for widget to accept style sheets.
I'm usually doing it like this:
void MyWidget::paintEvent(QPaintEvent *pe)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
QWidget::paintEvent(pe);
}