Is there a way to resize a QAction - pyqt

The QAction inside a QToolBar is away bigger than the icon I am using (16x16 or 32x32). How to resize a QAction to fit an icon without extra space. I tried to subclass, but I could find a method for the QAction to resize.
class MyAction(QAction):
def __init__(self)
super().__init__()
I tried to use setIconSize(QSize(32,32)), but it is not affecting the QAction it self. I believe this is related to the app stylesheet I am using, but I don't want to change that.
My current solution is to use a QToolButton, and addWidget inside the QToolBar(), is there better way ?
I am simply using a QMainWindow:
class Window(QMainWindow):
def__init__(self)
super().__init__()
self._Bar_1 = self.addToolBar('bar_1')
self._Bar_1.setIconSize(QSize(41, 41))
act1 = QAction(QIcon(r'icons\exit.png'), 'Exit', self)
self._Bar_1.addAction(act1)
I can't take a snapshot cause I need to hover or click the action to show its size, but it looks like this. I believe it is related to the stylesheet I am using:
This is ascrren shot I could get. notice, when hovering or press on the QAction in the first ToolBar, the action is seems too big for the icon inside ! Hope it helps
I am using the qt_material , find the link https://github.com/UN-GCPDS/qt-material

Related

Qt Designer make widget overlap another widget in layout

I want to make 3 window button like above picture (similar Google Chrome) use Qt Designer and PyQt.
I want 3 buttons overlap right side of TabWidget.
But I only can overlap the Button on TabWidget when break layout like the picture.
When I set any layout, every widget can not overlap on each other.
So can I overlap when set layout? Thanks.
This is the layout I want
It similar Google Chrome's layout
This cannot be done in creator/designer, and can only be achieved using setCornerWidget() from your code.
Since only one widget can be set for each corner, you have to create a QWidget that acts as a container, then add the buttons to it.
class Test(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
# ...
self.createButtons()
def createButtons(self):
# create the container and its layout
self.buttonContainer = QtWidgets.QWidget()
buttonLayout = QtWidgets.QHBoxLayout(self.buttonContainer)
# remove margins around the layout and set a minimal spacing between
# the children widgets
buttonLayout.setContentsMargins(0, 0, 0, 0)
buttonLayout.setSpacing(1)
# QToolButtons are usually better for this, as QPushButtons tend
# to expand themselves
self.minimizeButton = QtWidgets.QToolButton(text='_')
self.maximizeButton = QtWidgets.QToolButton(text='o')
self.closeButton = QtWidgets.QToolButton(text='x')
buttonLayout.addWidget(self.minimizeButton)
buttonLayout.addWidget(self.maximizeButton)
buttonLayout.addWidget(self.closeButton)
# set the container as the corner widget; as the docs explain,
# despite using "TopRightCorner", only the horizontal element (right
# in this case) will be used
self.tabWidget.setCornerWidget(
self.buttonContainer, QtCore.Qt.TopRightCorner)

Cannot position button content neither with anchor nor with justify

I have dynamic button label, which changes everytime you click it. The problem is, when text on the button changes, the same goes with button width. For this reason I set fixed width for my button.
After that, another problem appeared. Content is centered within button, so on every change image and label move a bit. For this reason I tried to position everything to the left side to reduce content trembling.
I looked through docs and found that button widget supports anchor option to position content. However, when I try it, I'm getting error:
_tkinter.TclError: unknown option "-anchor"
I found another option, justify, but result is the same:
_tkinter.TclError: unknown option "-justify"
Anyone knows how to deal with it? I'll share my code with you:
self.btnServiceIo = ttk.Button(
top_buttons_frame,
text="Usługa automatyczna",
image=self.ioBtnImg_off,
compound=tk.LEFT,
width=30,
justify=tk.LEFT,
anchor='w')
self.btnServiceIo.pack(side=tk.LEFT)
self.btnServiceIo.bind("<ButtonRelease>", self.IObuttonToggle)
(I don't use justify and anchor at the same time, I just posted them together to show you the way I'm using it)
I'll post the picture of my app for your attention. My client would like to have not only toggle image which states the status of some service, but also text information nearby.
For ttk buttons you can set the anchor option in the ttk style, see the anchor entry on this page.
So for example:
import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
root = tk.Tk()
s = ttk.Style()
s.configure('TButton', anchor=tk.W)
buttonImage = Image.open('test.png')
buttonPhoto = ImageTk.PhotoImage(buttonImage)
btnServiceIo = ttk.Button(
root,
text="Usługa automatyczna",
image=buttonPhoto,
compound=tk.LEFT,
width=30)
btnServiceIo.pack(side=tk.LEFT)
root.mainloop()
Answer from #fhdrsdg was almost perfect, but it messed with some of my simple buttons with text only, centered in the button. I had to make dedicated style for my button as following:
# Access ttk style object
s = ttk.Style()
# Set dedicated style for button, derived from main button class
s.configure('service-io.TButton', anchor=tk.W)
self.ioBtnImg_off = tk.PhotoImage(file='../img/io.png')
self.ioBtnImg_on = tk.PhotoImage(file='../img/io_on.png')
self.btnServiceIo = ttk.Button(
top_buttons_frame,
text="Usługa automatyczna",
image=self.ioBtnImg_off,
compound=tk.LEFT,
width=30,
style='service-io.TButton' # use dedicated style
)

PyQt adding a scrollbar to my main window

I want to add a scrollbar to my main window
Here's a simplified version of my code since mine is too long.
class Main(QtGui.QWidget):
def __init__(self):
super(Main, self).__init__()
verticalLayout = QtGui.QVBoxLayout()
self.setGeometry(0,0,400,400)
self.setLayout(verticalLayout)
label_1 = QtGui.QLabel("label 1")
self.verticalLayout.addWidget(label_1)
...(many more that exceed my computer screen)
so I've been reading a lot of posts about scrollbars but I'm still not quite sure as to how to implement it.
Within your main window, you need to create a Scroll Area.
http://pyqt.sourceforge.net/Docs/PyQt4/qscrollarea.html

PyQt check if value of qlabel changed

I Need to check if the value (str) of a qlabel changed.
I think about using the following code (nearly the same as used by a spinbox widget in PyQt):
self.connect(self.ui.labelEntry, QtCore.SIGNAL("valueChanged(str)"), self.autovalidate)
What's the correct Methode to check if value changed?
All the best;
QLabels don't have a valueChanged/textChanged signal. You either have to use another widget type (a QLineEdit for instance) or to subclass QLabel and create your own change-aware class with a textChanged signal.
If you use QtDesigner, it might be simpler to go with the first solution and customize your QLineEdit from the Designer. In the property editor, unckeck frame, check readOnly, and write background-color:"transparent" in styleSheet and you've got a QLabel looking QLineEdit.
You also should use the new-style syntax, it's far more elegant.
self.ui.labelEntry.textChanged.connect(self.autovalidate)

Getting pyqt application focus for popup menu to disappear when clicking away from it

Let me quickly explain the background to this. I'm developing a custom menu system inside a 3D application called Softimage XSI. It has a PyQt application object created already and ProcessEvents is being called a certain number of times every second so that PyQt applications can exist in a non-modal state within XSI.
To implement the menu, I've got a webpage embedded in a toolbar which is calling a plugin for XSI that I've written to show a PyQt menu. This all works fine (albeit, slightly contrived!).
The issue is that when I show the menu, it won't disappear when I click away from it. If I move the mouse over the menu, and then click away from it, it will disappear. It's only when it first pops up.
I've tried everything I can think of. Here's a list:
Using QtGui.qApp.installEventFilter(menu) to try and catch the mousepressed signal. It never gets triggered. I suspect the application itself isn't receiving the click.
Using menu.raise_() makes no difference
Neither does QtGui.qApp.setActiveWindow(menu)
Or menu.setFocus()
I've also tried:
event = QtGui.QMouseEvent(QtCore.QEvent.MouseMove, pos, QtCore.Qt.NoButton, QtCore.Qt.NoButton, QtCore.Qt.NoModifier)
QtGui.qApp.sendEvent(menu, event)
I had a go writing my own QEventLoop, but it just crashed XSI. I suspect trying to run a modal loop inside the other one probably isn't a legal thing to do. Either that, or I really don't know what I'm doing (equally probable)
The only thing I have partial success with is using grabMouse(). This is what makes the menu close if I click away from the menu (only after the mouse has passed over the menu once), but I have to call it a couple of times for it to "stick".
So this is my code at the moment:
class MyMenu (QtGui.QMenu):
def __init__(self, parent = None):
QtGui.QMenu.__init__(self, parent)
self.grabbed=2
def getMouse(self):
if self.grabbed>0:
self.grabMouse()
self.grabbed-=1
def paintEvent(self, event):
QtGui.QMenu.paintEvent(self, event)
self.getMouse()
def hideEvent(self, event):
self.releaseMouse()
def ShowMenu():
menu = MyMenu()
menu.addAction("A")
menu.addAction("B")
menu.addAction("C")
submenu = MyMenu()
submenu.addAction("D")
submenu.addAction("E")
submenu.addAction("F")
menu.addMenu(submenu)
menu.setTearOffEnabled(True)
menu.setStyleSheet("font: 8pt \"Sans Serif\";")
submenu.setStyleSheet("font: 8pt \"Sans Serif\";")
submenu.setTitle("Window")
submenu.setTearOffEnabled(True)
pos = QtGui.QCursor.pos()
pos.setX(105)
menu.popup(pos)
#Prevent garbage collection
QtGui.XSIMenu=menu
QtGui.XSISubMenu=submenu
#Desperate acts!
menu.raise_()
QtGui.qApp.setActiveWindow(menu)
menu.setFocus()
Any thoughts or random suggestions would be very gratefully received as this is driving me nuts! Don't be afraid to suggest modifications to stuff I've already tried, as I'm relatively new to PyQt and I may well have missed something.
Many thanks,
Andy
Just before calling popup with self.trayMenu.popup(QtGui.QCursor.pos()), call self.trayMenu.activateWindow(). Putting activateWindow before popup makes the left-click menu work the same as the right-click menu and it goes away when you click elsewhere. :)

Resources