Drawing areas and expose events - c++

I have a dialogue which contains a drawing area. I wish to redraw the contents of the drawing area if the dialogue is enlarged or shrunk or buried and exposed, as is normal and natural with drawing areas. To this end, I created a method
bool on_expose_event (GdkEventExpose *event);
in the class. But the presence of this event stops all the other widgets on the dialogue from being drawn correctly; presumably it is also being invoked when they are exposed. How do I create a function to refresh the drawing area only, and leave all the other widgets to take care of themselves?

You should really sub-class the Gtk::DrawingArea class and implement the on_expose_event() function from that class.

Related

Qt how to redirect widget painting to parent widget?

I'm creating some custom qt designer widget plugin for drawing purpose. With these widgets, user can use qt designer for drawing just like Microsoft Visio (hopefully).
As shown in the screenshot below, there are one SvPage object page_0 as the container, it contains one SvArc widget and one SvCircle widget.
Every thing is good, except that when one widget (A) cover other widget (B), user cannot select widget B easily.
To solve this problem, I'm trying to do:
Set the size of each drawing widget (eg. SvArc,SvCircle) to very small (40px * 40 px);
Paint the content of drawing widget direct to its parent widget (SvPage). In SvPage::PaintEvent(QPaintEvent event), it iterates all children drawing widgets and call the doPaint(QPainter painter) method of each children.
3. To refresh the drawing widget automatically (eg, when SvArc widget is moved, its drawing on SvPage should be updated automatically), in the drawing widget's SvArc::PaintEvent(QPaintEvent *event), it will trigger the SvPage to update its painting.
But in step 3, there is a problem that it will lead to recursive repaint issue:
because SvArc::PaintEvent() trigger SvPage::PaintEvent(), and SvPage::PaintEvent() will then trigger SvArc::PaintEvent() again since SvArc widget is a child widget of SvPage widget.
So, the question is that is it a good idea to redirect widget painting to parent widget? If yes, how to solve the recursive repaint issue? If no, what's the good one?
Code (simplified):
void SvPage::paintEvent(QPaintEvent *event)
{
initPainter();
QList<SvWidget*> widgets = this->findChildren<SvWidget*>();
for (int i = 0; i < widgets.count(); i++)
{
SvWidget* w = widgets.at(i);
w->doPaint(this->painter);
}
destoryPainter();
}
void SvWidget::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
emit signalDoPaint();
}
void SvArc::doPaint(QPainter* painter)
{
painter->drawArc(x, y, w, h, a alen);
}
You are messing things up here.
Every widget should be responsible for its own drawing. That's how Qt is designed to work.
You could use a single widget as a manager for some objects, and to draw them, but then those objects don't need to be widgets, they can be simple data representations. In that case, the objects will not concern themselves with any painting, it will be the manager widget that does it.
However that approach will be less efficient. Because when you have multiple independent widgets, the paint engine can easily detect changes and efficiently repaint only the parts that need updating.
In your case you will either have to do a whole lot of redundant repainting, or implement more sophisticated item management, which will be a complex task that will definitely not be worth the effort, if you are even up to it to begin with, which you are probably not.
Your current approach is very bad. I'd suggest to just stick to regular widgets, in their actual sizes, doing their actual painting. It will be much easier for you to implement and manage it, and it will be much easier for the computer to paint it.
As for selecting between overlapping widgets, QWidget wasn't really designed to facilitate that. Widgets are supposed to be put in layouts, not to overlap. Which is why its childAt() function can only return a single widget at a given coordinate.
What you should really do is use QGraphicsScene, QGraphicsView and QGraphicsItem. Similarly to widgets, graphics items will handle their own drawing efficiently, the difference is the API was designed for graphics, and when you have overlapping items, QGraphicsScene::items() will give you a list of all items at that position, so you can chose an item other than the topmost.
I'm creating some custom Qt Designer widget plugin for drawing purpose. With these widgets, user can use Qt Designer for drawing just like Microsoft Visio (hopefully).
The functionality you're reusing in Qt Designer is minimal, and could be easily factored out into a separate project. The only thing of any value for you is the property inspector pane.
For everything else, using widgets is about the most complicated way of implementing it. Use QGraphicsScene and QGraphicsView and start with 90% of your functionality already implemented and ready to go.
Implementing a rudimentary vector illustration system in QGraphicsScene is an afternoon job. You can have something with the functionality of early Corel Draw from Windows 2.x times done in a few days. It's the testament to the power of the scene framework and modern development frameworks in general.

How can I create a QPushButton with a custom (triangular) shape in Qt 5.5?

How can I create a triangular pushbutton in Qt? What is the most simplest way of executing this? I use the designer to create buttons and not code.
Also, I read somewhere that shapes may be changed as long as the frame of the button is still rectangular but I want the frame to adjust according to the shape as well. How can I achieve this?
More detail: I want to place lots of small triangular buttons next to each other with every other triangle flipped. Each triangle button has it's own function, etc (no overlapping borders accepted). Can anyone give me a descriptive explanation for how I might go about this?
The geometry on a QWidget is always a rectangle.
It would be possible to create a QPushButton derivative, override its paintevent and do some nasty painting considering its neighborhood etc. but it would be really a pain...
it is much easier to use a QGraphicsView, QGraphicsScene and add appropriate QGraphicsItem (maybe the QGraphicsPolygonItem?), add them and use their signals/slots or create a derived class for your purposes.
It is not that hard to override the mouseevents to recognize clicks and you can even use the QStyleSheets to let the "button" look like it gets pressed.

How to clear existing content before redrawing QGraphicsItem?

I have a drawing that is built inside a QGraphicsScene with several layers of QGraphicsItem derived objects.
I am repositioning the QGraphicsItem objects based on some parameters and have noticed that there are some "ghost" trails left unless I call graphicsArea->viewport()->update(). I am repositioning the QGraphicsItem objects quite frequently (i.e. when a slider is moved) and updating the viewport only works if I call it manually some time after drawing is finished (e.g. on a button click).
One possible solution that I found was to fill the background of each QGraphicsItem to be a neutral colour. This doesn't work when I have overlapping items though, as the underlying items can get overwritten.
Does anyone have any suggestions?
Thanks,
Alan

How to paint with QPainter only after a specific event?

I have a main window with some widgets on it, each needs its own graphic. I would like to use QPainter to draw shapes, lines, etc. on them, but only after a specific event, like the press of a button.
The problem is, if I just create a QPainter in any function, it won't work:
QPainter::setPen: Painter not active
The QPainter methods can only be called inside a paintEvent(QPaintEvent *) function! This raises the following problems:
I have to derive my custom classes for all the widgets I would like to paint on, so I can't use the Designer to place my widgets. This can get frustrating with a large number of widgets.
The widgets redraw themselves after each paint event of the window, like moving it around, or moving other windows in front of it. I do a lot of drawing in those widgets, so they will visibly blink in these cases.
Is there a better and simpler way to solve this? I started to think about just displaying images, and re-manufacturing those images only when the specific buttons are pressed. I doubt that it's the most elegant solution...
You can use custom widgets in the designer: Creating Custom Widgets for Qt Designer.
Qt Designer's plugin-based architecture allows user-defined and third party custom widgets to be edited just like you do with standard Qt widgets.
For your second question, one of the approaches is to create a QPixmap for each of your widgets. When your widget's appearance needs to be changed, you draw in that pixmap (using QPainter's constructor that takes a QPaintDevice - QPixmap is a QPaintDevice).
In your widget's paintEvent function, you simply fill your widget with that "cache" pixmap. This way, you only do the (potentially expensive) painting when it's actually necessary.

Displaying a popup widget in QT over application border

Let's say that I have an application frame, and I want to show a popup QCalendarWidget over on the right side of the frame. Normally, QT will clip the edges of the QCalendarWidget, cutting it in half and not displaying the rest, as it would be over the right side border.
Is there a way to work around this limitation without resorting to implementing a QDialog?
I want the widget to be visible outside the bounds of it's container.
If you'd show your Calendar, let's say, after a button click, as QDateTimeEditor does, it's contents will not be clipped, cause it do not belong to frame. It will be just a widget, that shows in a dialog manner. And maybe you should even place it in QDialog, that is modal and provides some convenience methods, rather then simple QWidget.
Btw, why don't you want to use QDatetimeEditor?