Scaling graphics in Qt - c++

I am writing a scheduling-type application using Qt/C++ and want to display weekly schedules in one part of the window, and have this rendering scale as the window size increases. The renders will be composed of rectangles with text in them, and as the display area increases the rectangles should scale nicely while the text should remain the same size.
I have experimented with QGraphicsScene and QGraphicsView and I can make rectangles and text scale; however, the rectangle scaling seems ugly (stretches the outline) and I don't want text to scale at all.
I suspect that I might want to resize the scene to the display area and re-draw the rectangles and text; however, I am not sure how to do this - QGraphicsScene doesn't seem to respond to resizeEvent. Is this even the right approach?

I'm not sure what the ugly rectangle scaling is about (a screenshot might help me understand better what you meant there), but if you don't want the text parts to scale, you can accomplish that by calling setFlag(ItemIgnoresTransformations, true) on your QTextGraphicItem objects.
As far as automatically rescaling the rectangles in response to a window resize, you might take a look at the documentation of the QGraphicsView::fitInView() method:
Scales the view matrix and scrolls the scroll bars to ensure that the
scene rectangle rect fits inside the viewport [...] It's common to
call fitInView() from inside a reimplementation of resizeEvent(), to
ensure that the whole scene, or parts of the scene, scales
automatically to fit the new size of the viewport as the view is
resized. Note though, that calling fitInView() from inside
resizeEvent() can lead to unwanted resize recursion, if the new
transformation toggles the automatic state of the scrollbars. You can
toggle the scrollbar policies to always on or always off to prevent
this (see horizontalScrollBarPolicy() and verticalScrollBarPolicy()).

Related

How to clip the corner rectangle created by two scrollbar controls

Let's say you have a resizable window with child scrollbar controls, and the scrollbars come and go depending on whether the window contents are large enough to require scrolling.
When both scrollbars are present, a small rectangle is effectively created in the bottom right corner of the window, at their intersection. Is there a clean strategy for clipping that rectangle when drawing on the window, so that you don't paint on it?
I guess my current approach is to obtain the rectangles for each scrollbar, and if those rectangles are not null, then use the rectangles' locations to determine the rectangle that we want to clip. And then call ExcludeClipRect for that rectangle. I guess a similar approach could be used, except with GetSystemMetrics(SM_CXVSCROLL) and GetSystemMetrics(SM_CYVSCROLL) to get the rectangle dimensions.
But is there a more accepted way of doing this, perhaps using some helpful clipping API functions? Thank you for any input.

C++ How do I stop resizing Sf :: Text on screen resize ( but at the same position)

Im making map editor and i want to add resizing window but when i resize window my gui elements are resizing too how can i stop that,
i stop resizing map surface with set new size of map view but i cant do it with gui elements because it changes positions of gui elements
if(events.type == sf::Event::Resized)
{
m_defaultViewSize.x = events.size.width;
m_defaultViewSize.y = events.size.height;
m_mapView.setSize(m_defaultViewSize);
m_mapView.setSize(m_mapView.getSize() / m_zoomScale);// Apply the zoom level
m_stateData->window->setView(m_mapView);
}
sorry for my poor english
If you currently DO NOT have a GUI view your rendering code might look something like:
m_stateData->window->clear();
m_stateData->window->setView(m_mapView);
m_stateData->window->draw(m_map);
m_stateData->window->draw(m_gui);
m_stateData->window->display();
This is drawing the GUI on the same view as the map, so if the map view changes so does the GUI. This might be fine if the map does not change, but if you are planning on moving, scaling or rotating the map it would be best to create a GUI view.
Now rendering might look like this:
m_stateData->window->clear();
m_stateData->window->setView(m_mapView);
m_stateData->window->draw(m_map);
m_stateData->window->setView(m_guiView);
m_stateData->window->draw(m_gui);
m_stateData->window->display();
This is fine until we resize the window.
After resizing the window the view stays the same even though the viewport has changed size. If the window has been made larger twice horizontally but not vertically, the GUI is going to be stretched horizontally.
I personally do not like stretching, I do not think it looks nice. We should resize the view.
You could resize the view the same way you resized the map view.
m_guiView.setSize(m_defaultViewSize);
m_guiView.setSize(m_guiView.getSize() / m_zoomScale);
This will stop resizing the GUI elements, but their position will be the same as if we had not resized the window. You might want to reposition the GUI elements. One simple way of doing this is by storing the GUI elements position as a ratio along the screen horizontally and vertically. So, the top left might be (-0.5, -0.5) and the bottom right might be (0.5, 0.5).
This might look like (with a view centered on (0, 0)):
// get ratio position of gui element
sf::Vector2f ratio_position = {
(m_gui.getPosition().x) / m_guiView.getSize().x,
(m_gui.getPosition().y) / m_guiView.getSize().y
};
// resize view
m_guiView.setSize(m_defaultViewSize);
m_guiView.setSize(m_guiView.getSize() / m_zoomScale);
// set position of gui element
m_gui.setPosition(
(ratio_position.x)* m_guiView.getSize().x,
(ratio_position.y) * m_guiView.getSize().y
);
You could also have this be functionality of a class.
You can use things other than ratios as well.
You could make GUI elements relative to corners of the screen, or other ratios. So You could have Health bar, Stamina bar, Mana bar all relative to the top left of the view. This would just be calculating the top left position (view center - half of the view size) and then adding on some relative position (for example, (0, 0) for health bar, (0, 32) for stamina bar etc).
I suggest you look at how other Game Engines handle GUI. Unity uses Anchor Points. Godot uses containers. Try and recreate a system you like.

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 resize QWidget in a layout while aligning it to the center and maintaining aspect ratio

Ok, so I'd like to display an image with qt where the image resizes with the browser and maintains the aspect ratio while also remaining centered in the window. I can get the resizing with aspect ratio to work correctly, but when I align it with Qt::AlignCenter, the qwidget no longer resizes (remains a fixed size). So basically, I can get either option to work but not together.
A good example of what I'm trying to do would be the imshow() function in matlab. This resizes the image while maintaining the aspect ratio and also centering the image in the window. The code I have is soemthing like this:
void roilayout::resizeEvent(QResizeEvent *event)
{
QSize p(roiview->refimage->size());
p.scale(roiview->view->size(), Qt::KeepAspectRatio);
roiview->view->resize(p);
}
and in the constructor:
roiview = new roiwindow;
roiview->view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
roiview->view->setCursor(Qt::CrossCursor);
roiview->view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
roiview->view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
QHBoxLayout *layoutContainer = new QHBoxLayout;
layoutContainer->addWidget(roiview->view);
setLayout(layoutContainer);
I searched google and couldnt find anything. Also asked a similar question a little while back but from the answers it appears I didn't ask the question clearly enough. Thanks.
A couple of things: First it would be helpful to know what type of control "view" is.
Also, I don't think you should need to resize the child control "view" (whatever type it is) within the parent's resizeEvent() callback.
A better solution might be to set the sizeHint policy on the child widget to automatically expand.

Stringray Grid transparent background

In Stringray grid, there is the ability to use a transparent background which allows the background of the dialog to be shown through the grid.
In the documentation it states:
But be careful; you should disable scrolling or you have to redraw the grid each time it is scrolled (by overriding DoScroll).
I have a scrollable gird and override the DoScroll and make sure I call Redraw and also tried Invalidate, however the grid is still not completely erasing and redrawing.
I also tried using the old drawing method by setting m_bForceOldDrawing to TRUE.
How can I create a grid that has a transparent background that paint correctly after a scroll without leaving artifacts?
Yes you have to redraw the grid by overriding DoScroll because it is no longer using ScrollWindow to scroll contents because the background is transparent.
However you now have artifacts of the grid over your background.
This is because the background behind the grid is not getting redrawn.
Do you have clipchildren set for the parent?
Another potential problem is that the background is not being drawn because it doesn't realize it has been exposed.
Try calling the parent with the following.
Parent.Invalidate();
Parent.UpdateWindow();
before calling...
Invalidate();