Separate Layers like feature on QGraphicsView - qt

In my QGraphicsView, I display a map. I need to display a horizontal ruler and a vertical ruler on the top edge and left edge respectfully.
The map needs to scrolled but the above rulers should be displayed at their fixed positions, but change their scale values.
I tried to implement this using drawForeground method. Due to the maps large size I only paint the visible area. So I need to update() every time scrolling is done. But this result sometimes flickers.
I feel it would be best to have separate layer like approach.
What is the best way to approach the problem?

The correct way to implement a ruler on the top and left is to derive from QGraphicsView, and then call in the constructor:
// add two rulers on top and left.
setViewportMargins(20, 20, 0, 0);
// add grid layout
QGridLayout* gridLayout = new QGridLayout();
gridLayout->setSpacing(0);
gridLayout->setMargin(0);
// create rulers
hRuler = new Ruler(Qt::Horizontal);
vRuler = new Ruler(Qt::Vertical);
// add items to grid layout
QWidget* corner = new QWidget();
corner->setBackgroundRole(QPalette::Window);
corner->setFixedSize(20, 20);
gridLayout->addWidget(corner, 0, 0);
gridLayout->addWidget(hRuler, 0, 1);
gridLayout->addWidget(vRuler, 1, 0);
gridLayout->addWidget(viewport(), 1, 1);
// finally set layout
setLayout(gridLayout);
This solution was initially presented here, and it works very well. The result looks like this.

I just changed ViewportUpdateMode of the graphics view to FullViewportUpdate to get away from flicker.
You can use SmartViewportUpdate for somewhat good results also.
The downside is, during animations, this takes more process power.

Related

QT : Masking an image - Suggestions?

I dont know if I am using the correct term here. However this is what I am trying to achieve and I would like some suggestions on how I could achieve that. I want to have a circle with border visible. Now here is the hard part and something I dont even know how to start with. I want to manipulate the circle in such a way that the borders of the circle are visible and its center is not (i.e Pretty much that it has a hole in it and would show what ever is placed under it)I would then like to have another image placed under the circle such that only the part of the image that is under the transparent part of the circle is shown the parts outside the transparent boundary of the circle become invisible. Any suggestions on how I could achieve this. It seems that googling isnt helping me.
I would suggest the alternative way for unmasking a circular area of an image. You can specify the clip region - the area where you need to perform painting. For example:
[..]
QPainter painter(this);
// Sample circular area.
QRegion r(QRect(100, 100, 200, 200), QRegion::Ellipse);
painter.setClipRegion(r);
[..]
painter.drawImage(0, 0, image);
[..]
This will draw only those parts of your image that are inside of the circle with radius 200. All the rest pixels will be hidden.
You can handle mouse move event to move this "circle" over the image like a loupe.
UPDATE
Below is the sample code that generates an image with circular mask and insert it into the label:
QPixmap target(500, 500); // the size may vary
QPixmap source("image.png");
QPainter painter(&target);
QRegion r(QRect(100, 100, 200, 200), QRegion::Ellipse);
painter.setClipRegion(r);
painter.drawPixmap(0, 0, source);
QLabel l;
l.setPixmap(target);
l.show();
You might want to have a look at the Composition Example.
In short you could draw the first image and then use one of the Composition Modes to draw the second image on top (or the other way around). Make sure to convert the images to ARGB32 before using them.
To make the inner Part of the Circle transparent you can adjust the Alpha Channel accordingly.
Here is a small Example using Composition mode:
QPainter p(&imageCircle);
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
p.drawImage(image);
p.end()
Here you can find the Qt Documentation of QPainter.

QGridLayout, 3 panes, not expanding properly

I'm trying to layout a window (all in code) with a QGridLayout. I can add widgets to the layout and they display in my window, but I can't figure out how to resize them properly. Here's what I'd like
[Leftmost][--------Center---------][Rightmost]
Those are the 3 "panes" of my window (all three of them lists). The left and right ones should be of a static width and hug their respective sides, and the center should expand to fill the width as the window grows (or shrinks).
Some code:
// Create the subviews, add them to a grid layout, and set the layout to the window.
QTableView *list = new QTableView(0);
list->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QTableView *flashList = new QTableView(0);
flashList->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QPushButton *infoButton = new QPushButton("Info!");
QPushButton *flashFeedsButton = new QPushButton("Flashfeeds");
QGridLayout *gridLayout = new QGridLayout;
// Set the minimum widths for all three columns of the grid
gridLayout->setColumnMinimumWidth(GridColumnFirst, 300);
gridLayout->setColumnMinimumWidth(GridColumnSecond, 300);
gridLayout->setColumnMinimumWidth(GridColumnThird, 300);
// Set the minimum heights for all rows of the grid
int headerFooterHeight = 44;
gridLayout->setRowMinimumHeight(GridRowFirst, headerFooterHeight);
gridLayout->setRowMinimumHeight(GridRowSecond, 200);
gridLayout->setRowMinimumHeight(GridRowThird, headerFooterHeight);
// Set the stretch factors
gridLayout->setColumnStretch(GridColumnFirst, 1);
gridLayout->setColumnStretch(GridColumnFirst, 2);
gridLayout->setColumnStretch(GridColumnThird, 1);
gridLayout->addWidget(list, 1, 0, Qt::AlignLeft);
gridLayout->addWidget(flashList, 1, 1, Qt::AlignCenter);
gridLayout->addWidget(infoButton, 0, 3, Qt::AlignRight);
gridLayout->addWidget(flashFeedsButton, 0, 1, Qt::AlignLeft);
_mainWindow->setLayout(gridLayout);
(As you might be able to tell, this is going to eventually be a 9x9 grid, but the point remains, I'm trying to get my middle row (GridRowSecond) to have the stretchy columns).
The rows themselves expand just fine. The problem seems to be getting the widgets at each cell to expand to take up their containing space. How do I do this? (also, vertically, my list is expanding properly, but not horizontally).
Look at the docs on QGridLayout::AddWidget:
The default alignment is 0, which means that the widget fills the entire cell.
But you have the following:
gridLayout->addWidget(list, 1, 0, Qt::AlignLeft);
gridLayout->addWidget(flashList, 1, 1, Qt::AlignCenter);
gridLayout->addWidget(infoButton, 0, 3, Qt::AlignRight);
gridLayout->addWidget(flashFeedsButton, 0, 1, Qt::AlignLeft);
Thus, you've specifically told the grid layout that you want your widget aligned to the left, center, right, and left of their cells, respectively. In your case you probably want to use the default alignment allowing the widgets to fill the cells and follow their own respective size policies.
It should just be a matter of setting the proper size policy on your widgets. So the buttons on the left and right:
button->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
and for the middle button
button->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
where the first argument defines the horizontal size policy and the second one defines the vertical size policy.
See the size policy documentation as well
You have a lot of variables going here (different widgets, different size policies on widgets, and size policies working on the layout itself, so it's a bit difficult to know where things are going wrong. A couple of suggestions:
1) First try to accomplish what you want with just one type of widget. For example, all QLabels with all Expanding size policies.
2) Only adjust the size policies of the widgets, I found that adding stuff in the grid layout starts making things confusing. The stretch factor for the widget's size policy should work fine.
3) Don't be afraid to try different ratios for stretch factors.
I've found that this is one of the things where Qt Designer (Creator) is helpful for puzzling these things out. It's much faster to adjust things in Designer and resize then the run compile cycle. After you have solved the issue there, you can take the properties you have found and put it in your code instead of a edit, compile, run.

Expanding a Qt Layout : how to put a widget on the right side and the let the other widget to fully fill the left?

I want to put a widget on the right side of a QHBoxLayout, and the other spaces should expand the left side. I've set the widget's SizePolicy to Expanding, but it's not valid. Anyone could offer some help? Thanks.
Code is here:
QHBoxLayout* tmplayout = new QHBoxLayout(this);
tmplayout->setContentsMargins(0, 0, 0, 0);
lineEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored);
tmplayout->addWidget(lineEdit, 0, Qt::AlignRight);
tmplayout->addWidget(pushButton, 0, Qt::AlignRight);
lineEdit should expand.
Try changing:
tmplayout->addWidget(lineEdit, 0, Qt::AlignRight);
tmplayout->addWidget(pushButton, 0, Qt::AlignRight);
To:
tmplayout->addWidget(lineEdit);
tmplayout->addWidget(pushButton);
When dealing with simple layouts like this, there is no need to specify alignments or stretch factors explicitly.
If you want to force pushButton to specific size, you can use setMinimumSize, setMaximumSize, and setFixedSize
Best regards
For the widgets you want to be on the left and expand, try to simply add them before the ones on the right, and add a 1 for their stretch factor. For example,
tmplayout->addWidget(exampleWidget, 1);
Then, you could simply add the widgets you want to be on the right side after the ones on the left, using just:
tmplayout->addWidget(lineEdit);
tmplayout->addWidget(pushbutton);
This will automatically give them a stretch factor of 0.
Since the stretch factor of exampleWidget in this example is 1 which is higher than the default 0, exampleWidget will expand; and, since you add it before the others, it will be on the left.
I am not sure if I understand your problem correctly, but maybe you need to look into QSpacerItem. If that is not helpful, maybe you can make a rough mock-up in Qt-Creator and post the screen shots (one example showing approx. what you have, one example showing what you want)
Try fixed or minimum size policies. Even you may want to fix the maximum width.

Problem with a Qt layout, I can not remove a space

Good morning,
I have to layout some QWidgets and layouts into a main layout, but I have a problem with a space that I can not remove.
Basically what I would achieve is a horizzontal layout containing a grid layout and some buttons ( all in a horizontal line ). The grid layout (2x2) contains 2 QLabels and 2 QLeds.
Unfortunately Qt place a space between the grid layout and the first button as you can see in the attached image here http://img413.imageshack.us/img413/9132/problemhu.png
I would remove such space.
Here the code I wrote:
QGridLayout* gl = new QGridLayout();
gl->setAlignment(Qt::AlignLeft);
gl->setContentsMargins(0, 0, 0, 0);
gl->addWidget(activeLabel, 0, 0);
gl->addWidget(m_focusLed, 0, 1);
gl->addWidget(encodingLabel, 1, 0);
gl->addWidget(m_encodingLed, 1, 1);
This created the grid layout and added the QLabels and QLeds on it.
Then I add the buttons into the horizontal layout so:
/* layout buttons */
QHBoxLayout* lo = new QHBoxLayout();
lo->setSpacing(0);
lo->addLayout(gl); // <--here I add the grid layout
lo->addWidget(m_goToBeginBtn);
lo->addWidget(m_goToEndBtn);
lo->addWidget(m_frewBtn);
lo->addWidget(m_fforBtn);
lo->addSpacing( 10 );
lo->addWidget(m_ffrewBtn);
lo->addWidget(m_ffforBtn);
lo->addSpacing(10);
lo->addWidget(m_prevBtn);
lo->addWidget(m_nextBtn);
lo->addWidget(m_playBtn);
lo->addWidget(m_stopBtn);
lo->addWidget(m_cutBtn);
lo->addSpacing(10);
lo->addWidget(m_zoomInBtn);
lo->addWidget(m_zoomOutBtn);
lo->addSpacing(10);
lo->addWidget(m_bgSndCheckBox);
lo->addWidget( m_showPanelBtn);
I don't know why Qt place such space between the grid layout and the first button. I would remove it. How can I do? I didn't get help from the Qt mailing list.
Best Regards
How to fix this largely depends on what behavior you want to see. I'm guessing what you want is for the labels and the Leds to stay exactly where they are, and keep their size.
What is happening is that the grid layout is resizing with your window, (like your buttons), but the left alignment is keeping the controls stuck to the left, thus the space.
First, remove the gl->setAlignment(Qt::AlignLeft) line.
Secondly, you want to make sure you set the sizePolicy properly on both your QLabels and your QLeds, because otherwise your QLeds will start to resize horizontally. What you want is a fixed horizontal size policy. Here is an example:
QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
sizePolicy.setHeightForWidth(label->sizePolicy().hasHeightForWidth());
label->setSizePolicy(sizePolicy);
A completely different way to accomplish the same thing would be to add a bunch of calls to setStretch() on your horizontal layout. But you would have to do this for each column in your layout that you want to stretch. Basically each for each button, but skipping the grid layout in the first column. Like this...
lo->setStretch(1, 1); // Column 1 is your first button
lo->setStretch(2, 1);
...
lo->setStretch(19, 1)l // 19 columns in total, 15 buttons plus 4 spacing.

Playing with Graphics in Flex

I was just going through one code used to draw one chart. This code is written in the updateDisplayList function of the ItemRenderer of ColumnChart. I am not good at the graphics part of Flex. Can anybody please explain me what this code is doing? I can see the final output, but am not sure how is this achieved.
var rc:Rectangle = new Rectangle(0, 0, width , height);
var g:Graphics = graphics;
g.clear();
g.moveTo(rc.left,rc.top);
g.beginFill(fill);
g.lineTo(rc.right,rc.top);
g.lineTo(rc.right,rc.bottom);
g.lineTo(rc.left,rc.bottom);
g.lineTo(rc.left,rc.top);
g.endFill();
Regards, PK
That code is drawing a rectangle, albeit in a bit of a roundabout way.
The drawing api in flash uses a "draw head". I can't see any reason for using g instead of graphics other than to save some typing. g.clear() erases anything that has been drawn before.
g.moveTo(rc.left, rc.top) moves that into position, in this case the top left corner of the rectangle (0,0). g.beginFill(fill) starts a fill, nothing surprising there.
The g.lineTo(x, y) calls move the draw head around to the the four corners of the rectangle and finally g.endFill() completes the fill.
You can get the same result doing this:
graphics.clear();
graphics.beginFill(fill);
graphics.drawRect(0, 0, width , height);
// this last call is only needed if you're going to draw even more,
// if not you can omit that too
graphics.endFill();
It basically draws a rectangle.
//clear any existing drawings
g.clear();
Set the current drawing position to the top-left corner of the rectangle, which is 0, 0
g.moveTo(rc.left,rc.top);
//start filling with the color specified by `fill`
g.beginFill(fill);
Draw a line to top-right corner of the rectangle from the current location (which is top-left corner). The lineTo method updates the current location so that subsequent drawings start from the new point.
g.lineTo(rc.right,rc.top);
Draw the remaining sides of the rectangle:
g.lineTo(rc.right,rc.bottom);
g.lineTo(rc.left,rc.bottom);
g.lineTo(rc.left,rc.top);
//end the fill.
g.endFill();
Check out the livedocs page for Graphics class for more info.
All the visual components in Flex inherit directly/indirectly from the UIComponent class. The updateDisplayList method of UIComponent draws the object and/or sizes and positions its children. This is an advanced method that you might override when creating a subclass of UIComponent. When you override it in your child class, you should call super.updateDisplayList with the correct parameters to make sure that the base class components are properly updated.
Degrafa makes this kind of thing much easier.

Resources