from PySide2 import QtGui,QtCore,QtWidgets
from PySide2.QtGui import*
from PySide2.QtCore import *
from PySide2.QtWidgets import *
from shiboken2 import wrapInstance
import maya.OpenMayaUI as mui
import sys
class ui(QWidget):
def __init__(self,parent):
super(ui,self).__init__(parent)
self.resize(300,500)
self.mainWindow = QtWidgets.QMainWindow(parent)
self.setupUI(self.mainWindow)
self.setFocus()
def setupUI(self,mainWindow):
mymainWindow = QWidget(mainWindow)
mymainWindow.resize(300,500)
def mousePressEvent(self,e):
print 'sdfasdf'
if e.button()==Qt.RightButton:
print "Clickkkk"
def Show(self):
self.mainWindow.show()
class app():
def __init__(self):
self.ptr = mui.MQtUtil.mainWindow()
self.ptr = wrapInstance(long(self.ptr),QtWidgets.QWidget)
self.ui = ui(self.ptr)
def runApp(self):
self.ui.Show()
self.ui.setFocus()
tt = app()
tt.runApp()
Here is the code I'm testing on. After using wrapInstance the mouseEvent are no longer working.
But if I didn't wrap it it's work
not working
class app():
def __init__(self):
self.ptr = mui.MQtUtil.mainWindow()
self.ptr = wrapInstance(long(self.ptr),QtWidgets.QWidget)
self.ui = ui(self.ptr)
def runApp(self):
self.ui.Show()
self.ui.setFocus()
working
I Also change some parent structure in UI class
class app():
def __init__(self):
self.ui = ui()
def runApp(self):
self.ui.Show()
Can anyone explain why the MouseEvent won't work after I wrap it? And how to make it work?
The crux of the problem is this: self.ui.Show(). This runs your custom method, which in turn runs this self.mainWindow.show(). This causes self.mainWindow to show, but you subclassed mousePressEvent for ui, not self.mainWindow! So it's not running the event because you're clicking on the wrong widget.
Instead, since ui is a QWidget, call self.ui.show(). You may also have to put self.setWindowFlags(QtCore.Qt.Window) in ui's constructor. With this the mouse event runs as expected when the user clicks on it.
Some side notes:
I doubt that you actually want to create a QMainWindow in a QWidget. It just strikes as odd. Consider sub-classing a QMainWindow instead as it should be the 'top' widget.
Also try to avoid importing modules like from PySide2.QtCore import *, and import them like this instead from PySide2 import QtCore. It's bad practice, pollutes your module's scope, and makes the code much more unreadable/un-maintainable since it's hard to traceback where these variables come from.
Oh, and for the love of god, use some vertical white-spacing :)
Related
blocking signals to reach QObjects is fairly simple with using the QSignalBlocker Class
like
# functionality
self.clickbuton.clicked.connect(self.printsomething)
self.clickbuton.clicked.connect(self.blockprint)
def printsomething(self):
print("dude")
def blockprint(self):
self.clickbuton.blockSignals(True)
what about custom slots like def printsomething(self): ?
trying the same operation but with blocking def printsomething(self): from printing
def blockprint(self):
self.printsomething.blockSignals(True)
will give a AttributeError: 'function' object has no attribute 'blockSignals'
it looks like this method works only for QObjects
how can I block def printsomething(self): from printing without using disconnect while its connected to the clicked signal?
code example
"""
Testing Template for throw away experiment
"""
import sys
import os
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5 import QtGui as qtg
class MainWindow(qtw.QWidget):
def __init__(self):
super().__init__()
# widget
self.clickbuton = qtw.QPushButton("click me")
# set the layout
layout = qtw.QVBoxLayout()
layout.addWidget(self.clickbuton)
self.setLayout(layout)
# functionality
self.clickbuton.clicked.connect(self.printsomething)
self.clickbuton.clicked.connect(self.blockprint)
def printsomething(self):
print("dude")
def blockprint(self):
self.printsomething.blockSignals(True)
# self.m_blocker = qtc.QSignalBlocker(self.clickbuton)
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())
What you're trying to do is to block a slot which is impossible.
You can only block signals of objects inherited from QObject.
As a solution you can instead of
def blockprint(self):
self.printsomething.blockSignals(True)
do this
def blockprint(self):
self.blockSignals(True)
that would block mainwindow signals until you turn blockSignals flag to false again.
I am creating a small GUI program using PySide. I am having difficulty creating another object of same class. What exactly I am trying to do is that when clicked on a button on MainWindow it should create another independent window of same class.
import sys
from PySide import QtCore, QtGui
class Sticky(QtGui.QMainWindow):
def __init__(self,parent = None):
QtGui.QMainWindow.__init__(self,parent)
self.initUI()
def initUI(self):
....
self.addToolBarElements()
....
self.show()
def addToolBarElements(self):
....
self.newwindow = QtGui.QAction(QtGui.QIcon(os.path.join(os.path.dirname(__file__),'icons/new.png')),"New Note",self)
self.newwindow.setStatusTip("New")
self.newwindow.triggered.connect(newwindow)
self.toolBar.addAction(self.newwindow)
def newwindow(self):
#how to create new object of same class
def run():
app = QtGui.QApplication(sys.argv)
notes = Sticky()
sys.exit(app.exec_())
Here is what I have tried:
I have tried multiprocessing but I didn't understand much. I tried calling run() method again but it gives error.
Do not call with the same name 2 different elements, in your case self.newwindow refers to the QAction as the method of the class, avoid it, that is a type of error easy to commit but difficult to find.
going to the point, you just have to create a new object of the class, but the problem is that the garbage collector will eliminate it, to avoid it there are 2 possible options, the first is to make the new window member of the class, or second store it in a list, that's the one I choose because I think you want to have several windows.
import sys
import os
from PySide import QtCore, QtGui
class Sticky(QtGui.QMainWindow):
def __init__(self,parent = None):
QtGui.QMainWindow.__init__(self,parent)
self.others_windows = []
self.initUI()
def initUI(self):
self.addToolBarElements()
self.show()
def addToolBarElements(self):
self.toolBar = self.addToolBar("toolBar")
self.newwindow = QtGui.QAction(QtGui.QIcon(os.path.join(os.path.dirname(__file__),'icons/new.png')), "New Note",self)
self.newwindow.setStatusTip("New")
self.newwindow.triggered.connect(self.on_newwindow)
self.toolBar.addAction(self.newwindow)
def on_newwindow(self):
w = Sticky()
w.show()
self.others_windows.append(w)
def run():
app = QtGui.QApplication(sys.argv)
notes = Sticky()
sys.exit(app.exec_())
run()
I'm making a large program in Python and using PyQt for the GUI. The whole program is divided into different modules so that different people can work on it simultaneously without interfering with the other people's work.
I am working on 3 different modules right now. 1 is the main program window that handles the basic UI and assigns widgets so the main window (this is not important, just so you know why the code doesn't look like a full program.)
First is the widget:
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui
from CustomButton import HoverButton #just a custom button class
from CustomGif import LblLoadingGif #where things go wrong
class Page1(QtGui.QWidget):
def __init__(self, parent=None):
super(Page1, self).__init__(parent)
self.lbl1GIF = LblLoadingGif(self)
self.lbl1GIF.move(400, 45)
self.btnStart = HoverButton(self)
self.btnStart.setText('Start')
self.btnStart.move(35, 400)
self.btnStart.clicked.connect(self.actStartGif)
#the code below works, but then I can only perform 1 action with each button
#self.btnStart.clicked.connect(self.lbl1GIF.actStart)
def actStartGif(self):
self.lbl1GIF.actStart
The code for the custom GIF looks as follows:
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui
class LblLoadingGif(QtGui.QLabel):
def __init__(self, parent=None):
QtGui.QLabel.__init__(self, parent)
self.setStyleSheet('background: url();')
self.setScaledContents(True)
self.resize(100, 100)
self.movLoadGif = QtGui.QMovie('Resources_Images/Loading6.gif', QtCore.QByteArray())
self.movLoadGif.setCacheMode(QtGui.QMovie.CacheAll)
self.movLoadGif.setSpeed(100)
self.setMovie(self.movLoadGif)
self.hide()
def actStart(self, event):
#print('test1')
self.show()
self.movLoadGif.start()
def actStop(self, event):
#print('test1')
self.hide()
self.movLoadGif.stop()
So the problem is that I can use the actStart function just fine when I call it from the button click directly, but not when I call it through another function. I have used a lot of different variations of brackets, self, Page1 when calling the actStart of the custom gif from withing the actStartGif function.
Any help will be appreciated.
When you use connect it is necessary to pass the name of the function since internally it is in charge of calling it, in your case you have to call it directly so you will have to pass its parameters, in this case event:
self.lbl1GIF.actStart({your value for event})
I do not understand why you use event for what happens to you None:
def actStartGif(self):
self.lbl1GIF.actStart(None)
I want to use signals for communicating between my view and my application controller. I have following approach but since I'm beginner in PyQt I don't know if that is the right one. Can anyone tell me If I am on the right path or are there better solutions?
EDIT: I have changed the example to a fully working example.
import sys
from PyQt4 import QtGui, QtCore
class View(QtGui.QMainWindow):
sigFooChanged = QtCore.pyqtSignal()
sigBarChanged = QtCore.pyqtSignal()
def __init__(self):
QtGui.QMainWindow.__init__(self)
central_widget = QtGui.QWidget()
central_layout = QtGui.QHBoxLayout()
self.__cbFoo = QtGui.QComboBox()
self.__cbBar = QtGui.QComboBox()
self.__cbFoo.currentIndexChanged[str].connect(lambda x: self.sigFooChanged.emit())
self.__cbBar.currentIndexChanged[str].connect(lambda x: self.sigBarChanged.emit())
central_layout.addWidget(QtGui.QLabel("Foo:"))
central_layout.addWidget(self.__cbFoo)
central_layout.addWidget(QtGui.QLabel("Bar:"))
central_layout.addWidget(self.__cbBar)
central_widget.setLayout(central_layout)
self.setCentralWidget(central_widget)
def setFooModel(self, model):
self.__cbFoo.setModel(model)
def setBarModel(self, model):
self.__cbBar.setModel(model)
class Controller:
def __init__(self, view):
self.__view = view
# Connect all signals from view with according handlers
self.__view.sigFooChanged.connect(self.handleFooChanged)
self.__view.sigBarChanged.connect(self.handleBarChanged)
self.__fooModel = QtGui.QStringListModel(["Foo1", "Foo2", "Foo3"])
self.__barModel = QtGui.QStringListModel(["Bar1", "Bar2", "Bar3"])
self.__view.setFooModel(self.__fooModel)
self.__view.setBarModel(self.__barModel)
def handleFooChanged(self):
print("Foo Changed")
def handleBarChanged(self):
print("Bar Changed")
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
view = View()
controller = Controller(view)
view.show()
sys.exit(app.exec_())
Personally, I don't create a separate generic controller class like that. It could be my own preference, but I tend to consider the actual QWidget class my controller, and the view is usually the GUI-only definitions that I generate from QtDesigner (Ui_Dialog for example), or create manually. And I make all my connections in the relevant QWidget.
Now on to your code, I don't know if you are just considering this snippet a general pseudocode example of the direction you are taking...but it has errors... I would normally suggest posting working code so people don't get confused as to whether you are having errors because of it, or just asking if its generally a correct direction to laying out code.
You are forgetting to call __init__() on the QMainWindow superclass.
I'm not sure what controller.show() would do (fail as of right now) because I don't see an example of how you intend to forward that show() command to your main window object? Again I don't really see why its even necessary to have that separate class.
Here is how I would see a more realistic example, again considering the QWidget classes themselves to be the controllers:
View
## mainUI.py ##
from PyQt4 import QtCore, QtGui
class Ui_MyWidget(object):
def setupUi(self, obj):
obj.layout = QtGui.QVBoxLayout(obj)
obj.cbFoo = QtGui.QComboBox()
obj.cbBar = QtGui.QComboBox()
obj.layout.addWidget(obj.cbFoo)
obj.layout.addWidget(obj.cbBar)
Non-Gui Library Module (Controller)
## nonGuiModule.py ##
class LibModule(object):
def handleBarChanged(self, *args):
print("Bar Changed: %s" % args)
Controller (any entry point)
## main.py ##
import sys
from PyQt4 import QtCore, QtGui
from mainUI import Ui_MyWidget
from nonGuiModule import LibModule
class Main(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.resize(640,480)
self._lib = LibModule()
self.myWidget = MyWidget(self)
self.setCentralWidget(self.myWidget)
self.myWidget.sigFooChanged.connect(self.handleFooChanged)
self.myWidget.sigBarChanged.connect(self._lib.handleBarChanged)
def handleFooChanged(self, *args):
print("Foo Changed: %s" % args)
class MyWidget(QtGui.QFrame, Ui_MyWidget):
sigFooChanged = QtCore.pyqtSignal(str)
sigBarChanged = QtCore.pyqtSignal(str)
def __init__(self, parent=None):
super(MyWidget, self).__init__(parent)
# this is where you set up from the view
self.setupUi(self)
self.cbFoo.addItems(['Foo1', 'Foo2'])
self.cbBar.addItems(['Bar1', 'Bar2'])
self.layout.addWidget(self.cbFoo)
self.layout.addWidget(self.cbBar)
# going to forward private signals to public signals
self.cbFoo.currentIndexChanged[str].connect(self.sigFooChanged)
self.cbBar.currentIndexChanged[str].connect(self.sigBarChanged)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv[1:])
view = Main()
view.show()
sys.exit(app.exec_())
There is an endless block when xml.etree.ElementTree.fromstring() function is called in the QThread. Also lots of other calls makes the QThread blocked like multiprocessing.Process().
Important to say that it is a pure block, no exception or break.
Here is the code (a little edited but same principle as the source):
from PyQt4.QtGui import *
from Ui_mainwindow import Ui_MainWindow
import sys
import xml.etree
class Bruton(QThread):
def __init__(self, mw):
super(Bruton, self).__init__(mw)
self.mw = mw
def run(self):
print("This message I see.")
tree = xml.etree.ElementTree.fromstring("<element>text</element>")
print("But this one never.")
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.init_bruton()
# When the form is shown...
def showEvent(self, arg1):
self.bruton.start()
def init_bruton(self):
self.bruton = Bruton(self)
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
The code as posted doesn't actually run, but with a couple minor changes it runs and works fine. Here is the code with modifications:
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
import xml.etree.ElementTree
class Bruton(QThread):
def __init__(self, mw):
super(Bruton, self).__init__(mw)
self.mw = mw
def run(self):
print("This message I see.")
tree = xml.etree.ElementTree.fromstring("<element>text</element>")
print("But this one never.")
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.init_bruton()
# When the form is shown...
def showEvent(self, arg1):
self.bruton.start()
def init_bruton(self):
self.bruton = Bruton(self)
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
And here is the output:
$ python test.py
This message I see.
But this one never.
This is with Python 2.6.6, PyQt4 4.8.3, on Debian Unstable.
Can you try it in your environment and see if my modified example works for you? If so, you are on the road to a solution for your real code. =)
The code I've shown here is shortened (the source is divided to two files and __ini__.py). I noticed that the main module must be the module that starts the QApplication. So I added app.exec_() to the __init__.py which is the main module of my program.