PaintEvent - Drawing on Custom Widget!



  • Is it possible to draw inside a QFrame?
    I have a Widget and I put it inside a QFrame.

    If I draw now, the paintevent draws everywhere but inside the Qframe.

    If I knew how to draw inside any Widget I want, I can put the Widget into the Qframe.

    I tried already something like this
    @QPainter painter(ui.widget);@

    or

    @painter.initFrom(ui.widget);@



  • Why is this not working either?

    its driving me crazy

    @ui.widget->setAttribute( Qt::WA_PaintOutsidePaintEvent);
    ui.widget->move(30,30);

    QPainter painter(this);

    painter.begin(ui.widget);
    

    painter.drawRect(22,11,9,22);@

    Let me explain this again, simple:

    I have a MainWindow, in this MainWindow I have one Widget,
    lets say it is on the position 300,300.

    Now I want to create a PaintEvent that draws inside that Widget.

    thanks for your help.



  • I think you are doing this overly complicated and most likely incorrect. Why do you pass ui.widget to QPainter begin()? I also suspect PaintOutsidePaintEvent is not what you want. Each widget should only be concerned with painting itself in the paint event so that it is clipped correctly against other widgets. Your paint event should not paint on other widgets. If you do it correctly, there are no problems with putting it inside a QFrame.

    What you want to do is to create your own QWidget subclass and do the painting from there. I found a usable example that shows the whole process here:

    http://www.serenethinking.com/2010/08/how-to-create-custom-widgets-with-qt/



  • okay thanks Jens, I am gonna give it a try.

    If you think it is easier to draw on QFrames,
    you are welcome to help me.

    I just tried that too, but couldnt find anything that works.



  • I still dont understand what you mean by "drawing on QFrame". You should not draw on other widgets at all. A widget should only draw on itself and not refer to other widgets inside of the paintEvent.

    Just create a QWidget subclass and re-implement paintEvent as in the example above. Draw everything you need and there should be no need to have pointers to other widgets there.

    After that you can put it inside a QFrame just like any other widget and Qt will ensure that your cust om child widget gets painted first, and then the QFrame paints itself on top of it.

    That said, if all you need is a frame around your custom painted widget, perhaps you could simply draw a rectangle yourself and avoid using a QFrame at all.



  • hmm I am creating some sort of a Tower Defense Game, its working better than I thought hohoho.

    Img: http://img21.imageshack.us/img21/1966/sniperdefense.jpg

    I am doing everything with QWidgets, and QLabel.
    They are in a QFrame and the QFrame is inside a MainWindow.

    Why am I using a QFrame?
    I want to be flexible moving all my widgets/labels/movies anywhere I want without changing thousands of variables. I only need to change the position of my QFrame and everything inside is moved as well.

    I tried to avoid Painter at all.

    But now I would like to add some lines connecting the sniper pointing to the monsters.
    I could also use a QImage but then I had to move the position and "rotating" the image,
    but that seems to be little too much work, especially the rotating.

    so I wanted to use a Painter to simply draw a line inside the QFrame!



  • The game looks really cool. Is the background 3D or static?

    You are achieving really impressive things with widgets that they were not primarily designed to do. It is more common/convenient for games to do all their painting inside a custom widget and create their own lightweight sprite class containing basic things like (int x, int y, image etc.) and do all of the painting in the paintEvent. (essentially it looks like you are using QLabel as a simple sprite now)

    In incomplete pseudo code it could look a bit like this:
    @
    class Sprite{
    int x, y
    QImage image
    void paint(const QPainter&);
    }

    drawMonsters(const QPainter &painter) {
    foreach(sprite in Sprites)
    sprite.paint(painter)
    }

    paintEvent(...) {
    QPainter painter(this)
    drawBackground(painter)
    drawMonsters(painter)
    drawCrossHair(painter)
    }
    @
    This way you will have direct access to all the features of QPainter everywhere. (which is essentially what you are trying to get right now) You would be able to draw curves and cross hairs directly into the scene using the same painter.

    Doing it this way would still allow you to move the scene around without changing "thousands of variables". You could for instance still put your gamecanvas widget inside a QScrollArea, or you could have a global viewPortPosition that you add when you draw the sprites.

    It might be a bit of work to change all of your drawing this way but it is probably better than trying to let widgets draw on top of each other but I think it would be worth it. If you want a simple hack that works, you can try to replace QFrame with QWidget subclass since it does not set a clip but essentially achieves the same.

    [Edit: Added @ tags around code -- mlong]



  • hi, thanks for your cheering words. =)

    sofar the background is static, actually everything is in 2d space.
    The monsters are .gif files so it looks pretty vivid when they are moving.

    the blood effect (you can see in the screenshot, I took that on purpose^^) is a Widget set with a background of .png files connected to a Timer, I posted this here already, that was one of the most trickiest parts I figured out.
    if someones cares http://qt-project.org/forums/viewthread/23005/

    so back to your saying:
    I am not sure if I can follow your pseudo code,
    I guess what you are piling on is above my skills.
    I liked to stick to QLabels/Moves and Widgets because everything was so easily to create
    and the performance was great. I can create up to 30-40 monsters that are moving through the path without caching the animations and everything works smoothly.

    I doubt if this would work with QPainter/PaintEvents.

    by the way for the future:
    If I want to use 3d backgrounds then I have to use Open GL, right?

    or do you mean by switching the backgrounds when scrolling through the Qframe?



  • I would argue my method would be simpler, not harder but you can save that for your next game. You will actually get better performance with painter/paintevent and more control over your game scene.
    Another suggestion is to look at the GraphicsView classes. QGraphicsItem is a little more lightweight than QLabel and provides built in collision detection.

    But performance doesn't really matter that much when computers are as powerful as they are. Good luck though. Your game already looks really fun and I happen to love tower defence games :)



  • maybe I just understood your saying little wrong.
    But the imagination to rewrite everything in QPainters little scared me,
    seems like lots of work

    but on ther other hand

    bq. built in collision detection.

    that sounds actually pretty awesome if it is what I think what it is.
    My first aim was actually creating a Tower Defense game where you can build the towers anywhere you like and the monster had to find a way through your "maze".
    but I gave up inventing such kind of algorithm, seemed to be a way too difficult, but if I can use a built in collision detection I may still implement later.

    But right now I have to postpone my plans to February after exams, QT is just one of six other subjects.

    So long story, thanks for the information.
    I'll take a close look at them 4 weeks later.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.