QQuickwidget grab image outside window area - qt

This is a sequel to another question here in which I was not precise while describing my goal.
As mentioned in the linked question, I wish to save a QML which is embedded in a QQuickWidget and it is larger than the window size. The QQuickWindow grabWindow() method captures only the window area and hence I tried the following code after I visually displayed it:
QQuickWidget* content..
content->setSource(QUrl("qml:/main.qml"));
QPixmap *pm = content->grab(QRect(QPoint(0,0),QSize(-1,-1));
pm->save("someFilename.png", 0, 100);
So, it is definitely not the issue of saving image after rendering. The used QML code is just a plain Rectangle. The proposed solutions in the previous question only grabs content falling within the window.
Any suggestions? Thanks! :)
Addendum:
I have tried the following but didn't work:
QImage paintdev(largeWidth, largeHeight, QImage:Format_RBG32);
content->render(paintdev, QPoint(0,0), QRegion(QRect(0,0,largeWidth, largeHeight), QWidget::DrawChildren);
paintdev.save(fileName, 0, 100);
This should by logic solve the issue of window size since there is no window. Any comments?

Ok, so I solved it by manually shifting the QML by the window height and saving all the images from the window captures and collate it to form the original image.
Not too much work though, but I am still mystified by the QWidget render() method which did not work.
Thanks for all the replies!

If your QML content is larger than the window size, the part that is out of screen is not drawn. Hence, there is no way to capture something out of screen, unless you use 2 monitors and extend view. This last approach would work.

Related

QTableView Zoom In/Out

I'm trying to create a QTableView that can be zoomed in and out like in Excel.
A similar question was asked here: Zooming function on a QWidget
However, I'm subclassing the QTableView in PyQt and not C so reimplementing the entire PaintEvent method is a bit evolved. The source code for that is a bit complex: https://qt.gitorious.org/qt/tiittane-qt/source/bdd4a9149789f60974603e1f7621d51378f0a108:src/gui/itemviews/qtableview.cpp#L1282
I'm looking to see if there are any other viable options to have a zoom able TableView. My first attempt was by setting the font size then realized each column and row widths would have to scale as well which can become slow. Then realized changing the font would change the print. It didn't seems like an elegant solution. Changing the scale of the painter before painting seems like the more elegant solution but would have to re-implement and translate quite a bit of code to python to do so. I'm wondering if there are any other hooks to get this done.
Thanks
If you can use QTableWidget instead then you can create a QGraphicsScene and add it to that. Then you easily control the scale of the widget within.
If you want vertical and horizontal headers always visible I think you will have to turn off the table's scrollbars (which would end up zoomed, probably not what you want anyways) and have the scrollbars part of the panel that contains the graphics scene (probably panel would be a QAbstractScrollArea with 4 cells in layout: one cell for scene, one for horiz scrollbar, one for vert scrollbar, and one for the corner maybe empty), and connect them to the table's scroll behavior.
There is no built-in method to zoom on a view.
The simplest way to separate the size of the font on the screen, versus the size of the font saved or printed, is to basically have two fonts. One to be displayed on the screen you can call 'zoom', versus the other to be saved/printed and call that 'font size'.
Note this answer is cut and pasted from the same question:
Zooming a view in PyQt?

qt: after moving window off-screen, how to move it back to default position, including default positioning behaviour?

[qt 4.8]
To get correct window dimensions including its frame, I do the following (as described e.g. here, see comment from Daniel Hedberg).
mainWindow.move(-50000, -50000);
mainWindow.show();
// do something with the window dimensions
mainWindow.move(0, 0);
mainWindow.show()
This works fine, however, I have a problem with the move(0,0) call: It makes the window always appear at position (0,0), while I would like to have the default behaviour, this is, the application only suggests to the window manager that (0,0) is a good place to position the window, and the WM might decide to shift it if necessary to avoid overlapping. In other words, I would like to switch back to Qt's default behaviour as if there weren't a call to move at all.
How can I do that?
One solution is to store Windows original position and use that. For extra safety (in case screen resolution changes), check that entire window still fits on screen and move and even resize if it does not.
A hacky alternative would be to create and open empty, possibly transparent dummy window of the same size and see where it gets positioned. Then move the original there and close the dummy one. Reading your question carefully, I think this would do what you are after.
I don't know of a Qt way to ask Window Manager to reposition the window, so if you really need that, specify the OS etc details.
Looking into the source code of Qt, I can now partially answer my own question: To convert a call to move into a suggestion for positioning instead of a request, do this:
mainWindow.move(100, 100);
mainWindow.setAttribute(Qt::WA_Moved, false);
mainWindow.show();
I've tested the code under X11 using Qt 4.8.4, and hopefully it works with on other platforms too.
Unfortunately, this doesn't solve the very problem I have, namely to use show to get the (decorated) dimensions of an off-screen window which then gets moved to the screen, calling show again. It seems that the first call to show directly sets platform-specific window manager flags which aren't completely reset and reevaluated in the second call. Actually, I'm going to think that this is a bug in Qt, so I'll report it accordingly.

Window flags not helping in mdiarea in Qt

I am using Qt and creating a GUI with multiple sub windows. I am using MDI Area for the same. I want to hide the top toolbar of mdi subwindow but using window flags is not helping.
I have tried writing the code as follows. First I tried for mdiarea and then for subwindow but neither worked.
mdiarea.setWindowsFlags(Qt::FramelessWindowHint);
subwindow.setWindowsFlags(Qt::FramelessWindowHint);
I have also tried using Qt::CustomizedWindowHint but even that is not helping. Please help me with this.
Thank You.
Try this:
mdiArea->addSubWindow(new QLabel("Qt::FramelessWindowHint"), Qt::FramelessWindowHint);
You don't want to set the MDI area itself as a frameless window, because it's a widget you likely have embedded in another window... it most likely already doesn't have a frame.
Your setting the 'subwindow' should work... but addSubWindow(myWidget) actually wraps the widget passed in in the real subwindow, so that's what was going wrong. Qt lets you pass in window flags as the second parameter of addSubWindow() and those flags go to the real subwindow.
Note that with a frameless window, you can't drag the window around to move it, or grab the edges to resize it, because there's nothing for you to grab onto!
If you just want the minimize and maximize buttons gone (but still want the close button), try passing Qt::Dialog instead.
Try also experimenting with these:
addSubWindow(new QLabel("Qt::Tool"), Qt::Tool);
addSubWindow(new QLabel("Qt::Tool|Qt::CustomizeWindowHint"), Qt::Tool|Qt::CustomizeWindowHint);
addSubWindow(new QLabel("Qt::Dialog"), Qt::Dialog);
I think Qt::Tool|Qt::CustomizeWindowHint is probably the best option (no buttons, but still movable and resizable - if you don't want it resizable, give it a fixed size (setFixedSize()).
Edit: Also try: Qt::CustomizeWindowHint|Qt::WindowTitleHint

Creating a permanent static overlay for QGraphicsView scene

I am making an app using Qt (currently 4.8) which displays a literal map from a large number of QGraphicsScene items. I would like to annotate the view with a scale. My requirement for the scale is that it is permanently fixed w.r.t the viewport widget. It needs to be updated whenever the view scale changes (zoom in, etc). There are other possible overlay items as well (compass, etc) so I'd prefer a generic solution.
I have looked at earlier questions around this which suggest:
using the ItemIgnoresTransform
using an overlay pixmap.
I tried IgnoresTransform but that way didn't work right: I couldn't figure out how to fix it in place in (say) the bottom corner of the viewport and was having some difficulty getting the text and lines always displaying in the correct size.
I scrapped that and subclassed QGraphicsView, adding an overlay pixmap by reimplementing the paintEvent (calls original one, then paints the overlay pixmap on top), and an alignment option to indicate where it goes. Coding some pixmap paint code produces a usable scale on the view. Yay! ... but it doesn't work with scrolls - I get "shattered" renderings of the scale all over, or sometimes no scale at all. I think this is because QGraphicsView::scrollViewportBy() uses viewport()->scroll() so I wondered if switching to ViewportSmartUpdate would help, but it doesn't help enough. I'd prefer not to switch to ViewportFullUpdate as that would likely slow the app down too much (there are millions of items in the scene and that would require a full repaint just to move around).
So. Any ideas from here? Would adapting my pixmap code to write to a new mostly-transparent Widget that is overlaid on the viewport be a better way?
Thanks for any help...
Though it may not be the best way of doing this, in the past I've added custom widgets to the window that holds the QGraphicsView / QGraphicsScene, which have the same graphic style as the QGraphicObjects in the scene. When the view is then used to move objects in the scene, or the scene itself, the items on the window remain in the same place.
Hope that helps.

Screenshot in a small part of Qt-Window

I would like to be able to take screenshots of my program and save them as png (or if it is possible as pdf). I have taken the screenshot-example from Qt. This takes a screenshot from the whole display. But I would like to take a screenshot from only a part of my window, even if it is in another postion of the display. How can I do that. Is there a function?
The static function grabWidget of QPixmap is your friend. You can easily take a pixmap of the provided widget and then save it in any format you desire:
QPixmap p = QPixmap::grabWidget(widget);
p.save("p.png");
What about QWidget::render (http://doc.qt.nokia.com/4.7-snapshot/qwidget.html#render)?
Examine the window to get it's position and size. If you have any specific element you want to see in the screenshot, you can get it's position and size instead. Otherwise, you'll have to use offsets from the window position which can cause trouble (for example, when the window is resized).
Get the screenshot and then crep the pixmap using the position/size from before.
There is one drawback: Taking a snapshot of the whole desktop is somewhat slow.
So a better solution might be to change your application: Render the parts you want to save in an off-screen buffer. You can then use this buffer to render the UI and save the screenshot at the same time.

Resources