I want to implement own QLayoutItem successor, but I can't provide QSizePolicy to layout, because no sizePolicy virtual method in QLayoutItem.
I looked into Qt sources and found that QLayout takes sizePolicy directly from QWidget avoiding QWidgetItem.
Why trolls have done so? And what I can do?
Setting sizePolicy using setSizePolicy ( QSizePolicy ) inside the constructor of your class implementing QLayoutItem doesn't work ?
Related
I am new to python, actually new to programming too, and I am recently working on a simple project with Tkinter. In this project, I was trying to create a force attention window and I finally got the answer from this page. The main codes are as follows:
import tkinter as tk
class App(tk.Tk):
TITLE = 'Application'
WIDTH, HEIGHT, X, Y = 800, 600, 50, 50
def __init__(self):
tk.Tk.__init__(self)
tk.Button(self, text="open popout 1", command=self.open1).grid()
tk.Button(self, text="open popout 2", command=self.open2).grid()
def open1(self):
PopOut1(self)
def open2(self):
# .transient(self) ~
# flash PopOut if focus is attempted on main
# automatically drawn above parent
# will not appear in taskbar
PopOut2(self).transient(self)
if __name__ == '__main__':
app = App()
app.title(App.TITLE)
app.geometry(f'{App.WIDTH}x{App.HEIGHT}+{App.X}+{App.Y}')
# app.resizable(width=False, height=False)
app.mainloop()
It worked though, one thing that I am still concerning is that why he specified a parameter in a class APP:
class App(tk.Tk):
However, there is nothing pass in the class when he called it:
app = App()
Can anyone answer it, or just give me some keyword that I can go search specifically. I have read some of the tutorials about class in python, but none of them mention it.
This is called inheritance. All parameters for creating an object of the class, like you did here: app = App(), are in the __init__ method.
class App(tk.Tk):
This part is not a parameter. Instead, this indicates that the App class inherits methods from the tk.Tk class. In essence, this is what turns your App class into a Tkinter application. Without it, you wouldn't have any of the functionality that Tkinter provides. Observe how at the bottom of your code, you create the app and then call app.mainloop(). Note that your App class has no mainloop method. It actually comes from the inherited tk.Tk class.
That said, this is a major topic in most languages so I don't doubt you'll find tons of resources to learn further if you simply search for "Python inheritance".
i want to trigger a messagebox from a button click without closing the entire application, I managed to do this in my previous project, but this time, the behavior is really unexpected. as soon as I clicked ok or the cross sign on the messagebox, the app also closing too without any error. here's the minimal example
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.set_and_load_ui()
def set_and_load_ui(self):
self.ui = QUiLoader().load('main.ui', self)
def trigger_messagebox(self):
self.messagebox()
def messagebox(self,x=""):
msg = QMessageBox(self)
msg.setIcon(QMessageBox.Information)
msg.setText("{}".format(x))
msg.setInformativeText("test")
msg.setWindowTitle("test")
msg.exec_()
app = QtWidgets.QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.ui.show()
# mainWindow.trigger_messagebox() #this is fine
mainWindow.ui.mainmenuButton.clicked.connect(lambda: mainWindow.trigger_messagebox()) #this is not fine
exit_code = (app.exec_())
just to check, if the messagebox itself is causing the problem, I tried to call it directly on my code, but turns out it just fine, but not when I tried to trigger it by a button click
The problem is related to the fact that QUiLoader loads the UI using the parent given as argument, and since the UI is already a QMainWindow, you're practically loading a QMainWindow into another, which is unsupported: QMainWindows are very special types of QWidgets, and are intended to be used as top level widgets.
It's unclear to me the technical reason for the silent quit, but it's certainly related to the fact that the loaded window actually has a parent (the MainWindow instance), even if that parent is not shown (since you're showing the ui).
Unfortunately, PySide doesn't provide a way to "install" a UI file to an existing instance unlike PyQt does (through the uic.loadUi function), so if you want to keep using PySide there are only two options:
do not use a main window in Designer, but a plain widget ("Widget" in the "New Form" dialog of Designer), load it using QUiLoader and use setCentralWidget() (which is mandatory, since, as the documentation also notes, "creating a main window without a central widget is not supported"):
self.ui = QUiLoader().load('main.ui', self)
self.setCentralWidget(self.ui)
The downside of this approach is that you cannot use the main window features anymore in Designer (so, no menus, status bar, dock widgets or toolbars).
use pyside-uic to generate the python code and use the multiple inheritance method to "install" it; the following assumes that you exported the ui file as mainWindow.py:
from mainWindow import ui_mainWindow
class MainWindow(QtWidgets.QMainWindow, ui_mainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
# no "set_and_load_ui"
self.mainmenuButton.clicked.connect(self.trigger_messagebox)
# ...
app = QtWidgets.QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
exit_code = (app.exec_())
As you can see, now you can access widgets directly (there's no ui object). The downside of this approach is that you must remember to always generate the python file everytime you modify the related ui.
I have a class that manages some shared resources and currently provides a get_X() and put_X() method to access the resources. A better interface for this would be to use a context manager for each resource as in
with ResourceManager.X() as x:
# do stuff
But my use is a QT5 Widget class that grabs the resource then it gets configured and has to release the resource when the widget is destroyed:
class MyWidget(QtGui.Widgets.QTableWidget):
def conf(self):
self.x = ResourceManager.get_x()
def closeEvent(self, event):
ResourceManager.put_x()
super().closeEvent()
So is there a more pythonic way analog to the context manager "with" construct to keep a resource allocated for the livetime of a class?
Note: Qt5 doesn't allow multiple inheritance
Update:
The Qt5 UI file loader doesn't allow passing arguments to __init__ so I have added the conf() method to configure custom widgets after the UI files are loaded. That's why the ResourceManager.get_x() isn't in __init__.
What I would like to do is to get rid of the put_x() call. I want the resource to be automatically freed by python when the class is deleted. There are many widgets and resources and it's easy to forget a put_x() somewhere so I don't want to balance get/put calls manually.
Another concern is exceptions when multiple resources are used. If the exception happens after say the 3rd resource then only those 3 should be released. Another thing I don't want to track manually.
Never used QT before, but the first thing that comes to my mind are the __init__ and __del__ methods, called respectively when a class instance is created and destroyed.
You could try the following:
class MyWidget(QtGui.Widgets.QTableWidget):
def __init__(self):
super().__init__()
self.x = ResourceManager.get_x()
def __del__(self):
ResourceManager.put_x()
super().__del__()
My unique concern is that QT actually deletes the class if it's not used anymore.
Try it and let me know
super().closeEvent()
Loading XRC wx.Panel on existing instance does not work.
There is no error reported, although on any attempt to display it's empty.
Erroneous method:
import wx
import wx.xrc
class SomePanelViewModel(wx.Panel):
def __init__(self, parent):
super().__init__()
xmlResource = wx.xrc.XmlResource('SomePanelView.xrc')
xmlResource.LoadPanel(panel=self, parent=parent, name='SomePanelView')
The XRC file is valid, because other method of LoadPanel works without a problem.
So the panel is populated and visible.
Working method:
xmlResource = wx.xrc.XmlResource('SomePanelView.xrc')
panel = xmlResource.LoadPanel(parent=parent, name='SomePanelView')
It is also worth to mention that both methods work for wx.Dialog without an issue.
I have also tried to run methods like 'Show' on broken panel.
Unfortunately without any effect.
I'm startled and confused.
Has anybody dealt with it before?
Any suggestions? Solutions?
So in the end I'm answering my own question. xD
The problem looks like a library bug.
Therefore I decided to make a workaround:
class XrcPanelView(wx.Panel):
def __init__(self, parent):
super().__init__(parent=parent)
xrcFilePath = 'path/to/your.xrc'
xmlResource = wx.xrc.XmlResource(xrcFilePath)
self._xrcPanel = xmlResource.LoadPanel(parent=self, name='ViewName')
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self._xrcPanel, 1, wx.EXPAND | wx.ALL, 0)
That way you inherit a panel and apply you XRC panel on it.
It's not a perfect solution.
Although it achieves my goal.
I needed to encapsulate some extra initialization steps within one view class.
Hope somebody would enjoy. ;)
I'm failing to start a multiprocessing.Process() instance inside a custom Qt Gui class. You can check the entire file (and the other files) from the project here.
However, when I create it outside of the class, in the main file, it works.
I have no idea why it behaves differently for those two ways.
(I don't know if it is relevant, but I'm running this program on a BeagleboneBlack, through "ssh -X", which shows the GUI windows on my computer. (I have to do this because one of the program's libraries can only run in the Beaglebone, because its GPIO interaction library).
Code inside the class (in the init() method) (this does not work, the GUI doesn't show up):
class MainWindow2(QMainWindow, Ui_MainWindow):
def __init__(self):
super(MainWindow2, self).__init__()
self.setupUi(self)
self.parent, self.child = multiprocessing.Pipe()
self.listener1=Listener(self.child)
self.listening_proc=multiprocessing.Process(target=listener1)
self.listening_proc.start()
Outside the class (this works):
parent, child = multiprocessing.Pipe()
listener1=Listener(child)
listening_proc=multiprocessing.Process(target=listener1)
listening_proc.start()