I'm using QWidget.grab to get a pixmap containing what a component currently displays. It works perfectly apart from the size of the component not suitable for my printing requirements.
Is there a way so I can grab the pixmap of the component in a particular size?
QPixMap.grab() in Qt5 and QPixMap.grabWidget() in Qt4 get a pixmap of a painted widget in the screen resolution which is the natural painting resolution. Using the rectangle parameter you can even get parts of widgets.
The natural output resolution is the widgets own screen resolution. But afterwards you can scale it to anything you like via QPixMap.scaled() so that it fits your printing requirements.
It would actually be nice to change (simple scale) the painting resolution when grabing. But I don't know of any way to achieve this.
Related
I was working on Qt Designer and I wanted to edit the background color (if possible a gradient) of QScrollBar but I don't know how to do it properly.
When I add any background color the whole widget changes color uniformly and becomes solid.
I was trying to change the color of the area behind the bar and arrow buttons only.
Unfortunately, with many complex widgets you can't just change a property with stylesheet without all the necessary implementation.
QScrollBar is one of those widgets, and in order to achieve background customization through stylesheets, at least all the following have to be provided too:
overall background color
add/sub-page color
handle color
add/sub-line ("arrow buttons") colors
To make the widget more visually responsive, borders (with pseudo-states for pressed/enabled/hover states) should also be provided, and adding images for arrow buttons is usually suggested (small arrows can be obtained through css border tricks, though).
The starting point is the official Qt stylesheet example documentation, which has a section for customizing QScrollBar.
Note that using a QProxyStyle is not an option, as many styles draw scrollbars in different ways, and sometimes they even ignore some "official" style functions like drawControl, because they take care of the whole painting within the drawComplexControl, using private functions.
I am currently trying to solve a problem with resizing Pixmap dynamically, I have a QLabel in one corner of my QMainWindow, from both sides surrounded by two different QSplitters when I change picture it is scaled by the size of the label with KeepAspectRatio. Both splitters also are connected with signal to a function that once again scales the pixmap to fit as much as it can.
The problem I ran into is, that I cannot figure out how to be able to decrease the size when the pixmap already fits all the space available, because at that moment the splitters just stop working.
This is the pixmap setup:
self.picture_field.setStyleSheet("border: 4px solid")
self.pixmap = QPixmap('dandelion.jpg')
self.picture_field.setAlignment(Qt.AlignCenter)
self.picture_field.setPixmap(self.pixmap.scaled(self.picture_field.width()-8,
self.picture_field.height()-8, Qt.KeepAspectRatio))
The -8 has to be there because of the border, if it was missing, the widget gets bigger with every change
One of the Qsplitters:
right_splitter = QSplitter(Qt.Vertical)
right_splitter.addWidget(self.picture_field)
right_splitter.addWidget(self.person_field)
right_splitter.splitterMoved.connect(self.dynamic_scaling)
Person_field is simple QTreeView
The dynamic scaling function:
def dynamic_scaling(self):
self.picture_field.setPixmap(self.pixmap.scaled(self.picture_field.width()-8, self.picture_field.height()-8, Qt.KeepAspectRatio))
EDIT: I tested it a little bit more, and it seems, that the pixmap reacts, but only once either the width or height is halved.
Judging by this statement, "I cannot figure out how to be able to decrease the size when the pixmap already fits all the space available, because at that moment the splitters just stop working", I think I know what the problem is. Every QWidget has a minimum size, available through the function QWidget.minimumSize. From experience I know that a QSplitter honors the minimum sizes of its children, and it will not allow the user to move the sash to a position that would force one of the children to take a size less than its minimum.
You say that one of the splitter's children is a QLabel. By design, QLabels are pretty smart about their own size requirements. If you change the text of a QLabel, for example, it will automatically recompute its size values and trigger a re-layout. I assume it does the same thing if you change the Pixmap, although I have not tried this myself. The point is that the QLabel's minimum size changes as its contents change.
Because of the dynamic resizing of the QLabel, and the refusal of a QSplitter to allow a child widget to violate its minimum size, the splitter may appear to "get stuck" and prevent you from making it smaller.
To fix this you need to make the QLabel have a minimum size that's very small, say (1,1). There are a few ways to do this. Since I don't have your complete application I can't be sure which one will work best for you.
Subclass QLabel and override minimumSize to return (0,0) This is pretty straightforward.
Set the size policy on the QLabel object to QSizePolicy.Ignore. See the docs for the function QWidget.SetSizePolicy.
Use the function QWidget.SetMimimumSize. I'm not sure this will work for QLabels since any change you try to make may get undone the next time you change the pixmap.
Replace your QLabel with a custom widget subclassed directly from QWidget. A generic QWidget has no minimum size, so your problem goes away. You will need to write a small function to set a new pixmap into your control, which will entail a paint event handler.
I hope that one of these methods will work for you (and that I have understood the problem correctly).
try that:
w = QtGui.Qlabel.width();
h = QtGui.Qlabel.height();
#set a scaled pixmap to a w x h window keeping its aspect ratio
QtGui.Qlabel.setPixmap(p.scaled(w, h, Qt.KeepAspectRatio))
now try to change h and w.
If you get any issues comment below.
π
Ώπππ
I have created a QGraphicsView and inside it a QGraphicsScene. I load a pixmap in the QGraphicsScene. Actually it's an inherited QGraphicsScene which implements a wheelEvent in order to make the zoom in/out function. Zoom function scales the pixmap by 10% up or down depending on the wheel's rotation. The scaling works fine, however the QGraphicsView size or QGraphicsScene size gets the value of maximum size of the rotation that was tried and not center any more. For example, If I scale it up using the wso that the scroll bars enabled then if I scale it down the scroll bars still are enabled and the pixmap goes at the top-left corner.
Any suggestions?
Edit: The scale function of QGraphicsView creates a low quality pixmap, that's why I don't use it. I'm adding a scaled pixmap and at every rotation I scale it again and project to GraphicsView. However the the size of GraphicsView or QGraphicsScene has resizing problems as mentioned before.
After a long time I found the solution to that. The problem was that the scene didn't follow the size of the pixmap. For example, when I was scrolling and created a large pixmap so that scroll bars were needed then if I was scrolling and created a small pixmap the scroll bars were still there cause the size of scene didn't change. However I found the solution to that by setting a rect in scene after adding the new pixmap. So Inside the wheelEvent (self, event) function, after clearing the scene by self.clear() and adding the new scaled pixmap, the size of scene need to change too. To do that I used the below command where self.__size is the new size of the scaled pixmap.
self.setSceneRect(QtCore.QRectF(0.0, 0.0, self.__size.width(), self.__size.height()))
Don't subclass the QGraphicsScene.
Subclass the QGraphicsView to get the wheel events, and change the view transformation accordingly. Set the world transform on the graphicsview using setTransform.
This is the proper way of doing it. Conceptually, the objects on the scene do not change size. It is your view that changes, you are zooming in/out. That's the camera moving, not the objects growing/shrinking.
You can use the level of detail in the paint method of the item to paint high or low-res versions of the image depending on the zoom factor.
There is a nice demo with 4000 chips where level of detail is used.
Someone know if it's possible to change the color of a pixel in a canvas without using un object, so without using something like canvas.create_oval or canvas.create_rectangle ?
There is no way to color a pixel other than to create a 1x1 pixel object of some sort. And yes, at some point you will experience performance problems. The canvas simply wasn't designed to be used this way.
If you're really needing to create a large area in which you can manage individual pixels, you can create a canvas with a single image that is the same size as the canvas. You can then set the color of individual pixels on the image through the photo image interface.
Within tkinter itself, it's impossible.
Even if you manage to change a pixel on canvas window (which is possible with X11 and Windows APIs in a platform-dependent way), you'd have to ensure it's repainted properly.
You can, of course, place a frame of size 1x1 over the canvas, with a background color you want. This way, pixel is "changed" and no canvas object is created. If there's a real (though strange) problem behind a question, this trick could be a solution.
Ideally, the transparent border.
Here's an example of what i'd like to achieve:
Notice the transparent border.
Now i suppose I could use cairo to create a rectangle with transparency, and put a borderless non-transparent window inside, mimic'ing that effect - which I would if i knew the window would have a fixed dimension. However, if the inner window grows, it'll grow out of the transparent rectangle.
How should one approach such task?
Making window frames is really the job of the window manager (at least under X11, don't know how it works on windows).
But have a look at the GtkBin, GtkBox or GtkMisc widgets. Pack the dialog inside it as a single widget, and use padding to give it a size. Read up on GTK+ drawing model. You will probably need to set a flag and define your own expose-event handler to re-draw your frame.