The title of the window doesn't display event.x && event.y (see the code :D) .
I discover the method do_configure_event doesn't been called.
new to pygtk,
many thx! :D
#!/usr/bin/env python2.7
# encoding:utf8
# sources: zetcode
import gtk
import gobject
class pyapp:
__gsignals__ = {
"configure-event" : "override"
}
def __init__(self):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.connect("destroy", gtk.main_quit)
self.window.set_size_request(350,200)
self.window.show_all()
def do_configure_event(self, event):
title = "%s, %s" % ( event.x, event,y)
self.window.set_title(title)
gtk.Window.do_configure_event(self, event)
pyapp()
gtk.main()
Name your sources! It seems you're trying to adapt example code from Zetcode you do not fully comprehend.
Your problem is: to put your class attribute __gsignals__ into use, you have to derive from gtk.Window. The window instance looks up the signals and therefore its gsignals dictionary has to be filled. At the moment, this dictionary resides in pyapp.
Related
I am trying to code a program based on traitsUI and Mayavi, but I have some problems. Following the code I am using:
#!/usr/bin/env python
import os
from traits.api import HasTraits, Instance, String, on_trait_change
from traitsui.api import View, Item
from tvtk.pyface.scene_editor import SceneEditor
from mayavi.tools.mlab_scene_model import MlabSceneModel
from mayavi.core.ui.mayavi_scene import MayaviScene
class ActorViewer(HasTraits):
scene = Instance(MlabSceneModel, ())
view = View(Item(name='scene',
editor=SceneEditor(scene_class=MayaviScene),
show_label=True,
resizable=True,
dock='tab',
height=500,
width=500),
resizable=True
)
def __init__(self, engine=None, **traits):
HasTraits.__init__(self, **traits)
if engine is not None:
self.scene=MlabSceneModel(engine=engine)
else:
self.scene=MlabSceneModel()
self.generate_data()
#on_trait_change('scene.activated')
def generate_data(self):
src=self.scene.mlab.pipeline.open(Path+i)
self.scene.mlab.view(40, 50)
self.scene.mlab.pipeline.outline(src)
self.scene.mlab.pipeline.iso_surface(src, contours=60, opacity=0.5)
if __name__ == '__main__':
Path = "/path/to/my/folder"
filelist = os.listdir(Path)
for i in filelist:
if i.endswith(".vtr"):
if ("E1_" in i) or ("E2_" in i):
print("file name ", i)
a = ActorViewer()
a.configure_traits()
The call self.scene.mlab.view(40, 50) returns AttributeError: 'NoneType' object has no attribute 'active_camera', thus I don't know how to set the camera. I have read that it is related to when the scene is activated, but I couldn't find a solution.
Without setting the view, the code works, but each file is loaded and rendered alone. In order to proceed with the main loop, each render has to be closed. I would like to dock each of the file without closing them.
I couldn't find a way to set a custom label to each tab after allowing show_label=True and to have it aligned horizontally at the top of the scene.
I tried to set the outline with the 'cornered' layout, but I couldn't find a way to do that. self.scene.mlab.pipeline.outline.outline_mode('cornered') gets simply ignored.
Thank you for your help!
I'm new to working with PyQt for GUI development. As a tutorial for one of the trainings, I'm to develop a phone dialer, which basically just displays a number pad and makes the appropriate dial tones when pressed. This involves importing a resource file that contains the 12 tones. i downloaded the tones from the internet and tested them. They all work just fine. however after I create the resource file, and convert it using pyrcc5, the tones do not play. I've copied the resources.py from the tutorial and the dial pad works as expected. I'm wondering if anyone can help me debug this issue. I haven't seen anything online that shows a similar problem.
if someone can help me attach files, I can add the resource files to the question as well.
Here is a copy of my code although it doesn't appear to be the problem:
import sys
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5 import QtMultimedia as qtmm
import resources1
class SoundButton(qtw.QPushButton):
def __init__(self, wav_file, *args, **kwargs):
super().__init__(*args, **kwargs)
self.wav_file = wav_file
self.player = qtmm.QSoundEffect()
self.player.setSource(qtc.QUrl.fromLocalFile(wav_file))
self.clicked.connect(self.player.play)
class MainWindow(qtw.QMainWindow):
def __init__(self):
"""MainWindow constructor.
This widget will be our main window.
We'll define all the UI components in here.
"""
super().__init__()
# Main UI code goes here
dialpad = qtw.QWidget()
self.setCentralWidget(dialpad)
dialpad.setLayout(qtw.QGridLayout())
for i, symbol in enumerate('123456789*0#'):
button = SoundButton(f':/dtmf/{symbol}.wav', symbol)
row = i // 3
column = i % 3
dialpad.layout().addWidget(button, row, column)
# End main UI code
self.show()
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
# it's required to save a reference to MainWindow.
# if it goes out of scope, it will be destroyed.
mw = MainWindow()
sys.exit(app.exec())
Thanks in advance for your help
I have the following code to replace a widget (self.lbl) each time I click on a button (self.btn):
import sys
from PySide2.QtCore import Slot
from PySide2.QtWidgets import QApplication, QLabel, QVBoxLayout, QWidget, \
QPushButton
class Workshop(QWidget):
def __init__(self):
super().__init__()
self.n = 0
self.btn = QPushButton('Push me')
self.lbl = QLabel(str(self.n))
self.main_layout = QVBoxLayout()
self.sub_layout = QVBoxLayout()
self.sub_layout.addWidget(self.lbl)
self.sub_layout.addWidget(self.btn)
self.main_layout.addLayout(self.sub_layout)
self.btn.clicked.connect(self.change_label)
self.setLayout(self.main_layout)
self.show()
#Slot()
def change_label(self):
new_label = QLabel(str(self.n + 1))
self.main_layout.replaceWidget(self.lbl, new_label)
self.n += 1
self.lbl = new_label
if __name__ == '__main__':
app = QApplication()
w = Workshop()
sys.exit(app.exec_())
Right after its initialization, the object w looks like this:
When I click on the "Push me" button (self.btn), the number is incremented as wanted, but the initial "0" remains in the background:
But the other numbers do not however remain in the background ; only "0" does. Fore example, here is "22" (result after I clicked 22 times on "Push me"):
Note: I know that I could achieve the resultant I want with the setText method, but this code is just a snippet that I will adapt for a class in which I will not have a method like setText.
Thank you!
When you replace the widget in the layout, the previous one still remains there.
From replaceWidget():
The parent of widget from is left unchanged.
The problem is that when a widget is removed from a layout, it still keeps its parent (in your case, the Workshop instance), so you can still view it. This is more clear if you set the alignment to AlignCenter for each new QLabel you create: you'll see that if you add a new label and resize the window, the previous one will keep its previous position:
class Workshop(QWidget):
def __init__(self):
# ...
self.lbl = QLabel(str(self.n), alignment=QtCore.Qt.AlignCenter)
# ...
def change_label(self):
new_label = QLabel(str(self.n + 1), alignment=QtCore.Qt.AlignCenter)
# ...
You have two possibilities, which are actually very similar:
set the parent of the "removed" widget to None: the garbage collector will remove the widget as soon as you overwrite self.lbl:
self.lbl.setParent(None)
remove the widget by calling deleteLater() which is what happens when reparenting a widget to None and, if it has no other persisting references, gets garbage collected:
self.lbl.deleteLater()
For your pourposes, I'd suggest you to go with deleteLater(), as calling setParent() (which is a reimplementation of QObject's setParent) actually does lots of other things (most importantly, checks the focus chain and resets the widget's window flags), and since the widget is going to be deleted anyway, all those things are actually unnecessary, and QObject's implementation of setParent(None) would be called anyway.
The graphic "glitch" you are facing might depend on the underlying low-level painting function, which has some (known) unexpected behaviors on MacOS in certain cases.
I have a QMainWIndow called Main which calls QDialog called popup_on_waiver. QDialog has a combobox to select number of hours. Once user selects hours and clicks Ok, I want to close the popup, hide the QMainwindow and launch the QMainwindow after selected number of hours from combobox. Program works until user selects hours and cliks ok. It closes popup and hides main window.(Requirement is that app has to be running in hidden forever, so hiding the main window). When it calls launch_after_interval, its failing with error "Process finished with exit code 1073741845". Please advise on the correct steps.
I am launching the Main window on certain other conditions that are not provided below so I am writing a separate block for launching the main window again after waiver hours selected by the user. Also, I tried to fetch the result of popup window, accepted or rejected but it didnt return anything.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import QUrl, Qt, QTimer, QSize, QRect
import sys
class popup_on_waiver(QDialog):
#pop up window
def __init__(self, parent=None):
super(QDialog,self).__init__(parent)
self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.setMinimumSize(QSize(660, 340))
self.setWindowTitle("Waiver")
self.cb = QComboBox() #combobox
self.cb.setGeometry(QRect(40, 40, 100, 30))
self.cb.addItems(["1", "2", "3", "4"])
self.cb.currentIndexChanged[str].connect(self.returnInterval)
self.cb.setObjectName("combobox")
self.cb.move(80, 80)
self.buttons = QDialogButtonBox(
QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
self.buttons.accepted.connect(self.hide_main)
self.buttons.rejected.connect(self.reject) #buttons
vbox = QVBoxLayout(self) #layout
vbox.addWidget(self.cb)
vbox.addWidget(self.buttons)
self.setLayout(vbox)
def hide_main(self, hours):
self.accept
self.parent().hide()
launch_after_interval(self.interval) #calling timer function
def returnInterval(self, hours): #combobox value that is number of hours
self.interval = int(hours) * 3600 * 1000
#QMainwindow
class Main(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.initUI()
def initUI(self):
self.centralwidget = QWidget(self)
self.Waiver = QPushButton('Waiver')
self.Waiver.clicked.connect(lambda: self.popup())
hbox = QHBoxLayout()
hbox.addWidget(self.Waiver)
self.centralwidget.setLayout(hbox)
self.setGeometry(50, 50, 1200, 600)
self.setWindowTitle("Timesheet")
self.setWindowIcon(QIcon(""))
self.setStyleSheet("background-color:")
self.setCentralWidget(self.centralwidget)
self.show()
def popup(self):
self.p = popup_on_waiver()
self.p.exec_()
def launch_after_interval(interval):
timer = QTimer()
timer.setSingleShot(True)
timer.setInterval(interval)
timer.timeout().connect(lambda: Main())
timer.start()
There are various problems with your code:
you create the dialog without setting the parent, so when you try to call self.parent().hide() it won't work because parent() returns None, which obviously doesn't have a hide attribute;
you have connected the accepted signal to hide_main, which requires an argument, but the accepted signal doesn't have any;
you missed the parentheses of accepted in hide_main, so it wouldn't be called;
self.interval is set only whenever the index of the combo is changed, but if the user doesn't change it (by leaving the default value), there won't be any self.interval set;
you are setting the WindowStaysOnTopHint flag only, which will reset any other window flags; the result will be that you won't have a new window, but a widget that is "embedded" in the parent; to correctly set the flag you should use self.setWindowFlags(self.flags() | Qt.WindowStaysOnTopHint);
signals cannot be "called", so there should be no parentheses in timer.timeout().connect;
the timer object has no reference outside the scope of launch_after_interval, nor it has no parent object set, so it will be deleted as soon as the function returns and will never be fired;
Revised code (modifications are in bold):
class popup_on_waiver(QDialog):
def __init__(self, parent=None):
super(QDialog,self).__init__(parent)
self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)
self.setMinimumSize(QSize(660, 340))
self.setWindowTitle("Waiver")
self.cb = QComboBox() #combobox
self.cb.setGeometry(QRect(40, 40, 100, 30))
self.cb.addItems(["1", "2", "3", "4"])
self.cb.currentIndexChanged[str].connect(self.returnInterval)
self.cb.setObjectName("combobox")
self.cb.move(80, 80)
self.buttons = QDialogButtonBox(
QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
self.buttons.accepted.connect(self.hide_main)
self.buttons.rejected.connect(self.reject)
vbox = QVBoxLayout(self)
vbox.addWidget(self.cb)
vbox.addWidget(self.buttons)
self.setLayout(vbox)
# set the default interval
self.interval = 3600000
# no arguments here!
def hide_main(self):
self.accept() # <-- the parentheses!
self.parent().hide()
launch_after_interval(self.interval)
def returnInterval(self, hours):
self.interval = int(hours) * 3600 * 1000
class Main(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)
self.initUI()
def initUI(self):
self.centralwidget = QWidget(self)
self.Waiver = QPushButton('Waiver')
# if the function does not have arguments, lambda is usually not required
self.Waiver.clicked.connect(self.popup)
hbox = QHBoxLayout()
hbox.addWidget(self.Waiver)
self.centralwidget.setLayout(hbox)
self.setGeometry(50, 50, 1200, 600)
self.setWindowTitle("Timesheet")
self.setWindowIcon(QIcon(""))
self.setStyleSheet("background-color:")
self.setCentralWidget(self.centralwidget)
self.show()
def popup(self):
# the parent is required to make the dialog modal *and* allow it
# to call parent().hide()!
self.p = popup_on_waiver(self)
self.p.exec_()
def launch_after_interval(interval):
# set a parent QObject for the timer, so that it's not removed
# when the function returns
timer = QTimer(QApplication.instance())
timer.setSingleShot(True)
timer.setInterval(interval)
timer.timeout.connect(lambda: Main())
timer.start()
Other relatively minor issues:
similar attribute names (like centralwidget, which is too similar to QMainWindow's centralWidget()) should be avoided, as they can create confusion and lead to hard to find bugs and issues;
a timer that acts on an object should not be created outside of the object that will eventually call/access/show it (even if indirectly); while technically there's nothing wrong with it, it's usually better to keep objects "organized", so that they can be accessed if required (for example, showing the window and stopping the timer before it times out);
creating a new instance of the main window is not suggested, as one already exists; this is related to the previous point: if you have a direct reference to the timer and the window, you can also call self.someWindow.show();
avoid mixing and confusing naming styles: you've used upper case names for attributes (Waiver) and lower for classes (popup_on_waiver), while it should be the opposite; then there's also mixedCase (returnInterval) and under_score (hide_main); choose a style and keep that one (read more about it in the style guide for Python code, aka PEP-8);
I preferred to edit only the parts of your code that prevented the program to work, but you should really keep the aspects above in mind, even if they are "relatively minor" (emphasis on relatively).
Finally, (trivial, but not irrelevant): mixing import modes from the same modules should be avoided: you either use wildcard imports like from module import * (but you normally shouldn't) or explicit ones like from module import ClassA, ClassB, [...]; for big modules like PyQt5, it's common to import the submodule, like from PyQt5 import QtWidgets:
Good:
from PyQt5 import QtWidgets
class SomeWidget(QtWidgets.QWidget):
# ...
Also good, but tends to be very obnoxious as you have to remember to add classes each time you need a new one and you might end up with a really long list of imports, possibly resulting in unnecessary classes as you ended up in not using some (also, I doubt there's a substantial benefit, at least on Qt):
from PyQt5.QtWidgets import QWidget, QHBoxLayout # etc...
class SomeWidget(QWidget):
# ...
Not so good, but it works (keeping submodule names can be useful to keep also in mind their "scope") and behaves as the previous one:
from PyQt5.QtWidgets import *
And this, this is simply wrong (I mean, it works, but it doesn't make any sense):
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QWidget
I've got the code below, and I was planning on making several classes all within the same "import". I was hoping to instantiate each class and get a return value with the widgets I'm making.
This isn't really a PyQt question at all, more of a "good practices" question, as I'll have a class for each widget.
Should I make functions that return the widgets that were created, if so how? How do I ensure it is difficult to directly instantiate the class if that is the best method for what I'm after?
I'd like to be able to do something like ....
tabs = wqTabWidget( ['firstTab', 'Second', 'Last Tab'] )
or (which ever is a better practice)
tabs = wqInstance.createTabs( ['firstTab', 'Second', 'Last Tab'] )
Here's my class so far....
from PyQt4 import QtCore as qc
from PyQt4 import QtGui as qg
class wqTabWidget(qg.QTabWidget):
def __init__(self, *args):
apply(qg.QTabWidget.__init__,(self, ))
tabList = []
tabNames = args[0]
for name in tabNames:
tabWidget = qg.QWidget()
self.addTab(tabWidget, name)
tabList.append( { name:tabWidget } )
print 'hi'
if __name__ == '__main__':
app = qg.QApplication(sys.argv)
window = wqTabWidget(['hi', 'there', 'and', 'stuff'])
window.show()
app.exec_()
The answer will be decided if the list of tabs can be changed at runtime. If this widget really only supports adding a set of tabs, but never changing or appending new ones, the list of tabs should come from the initializer. Otherwise you should also add a method to do the job. Consider the QLabel widget which can set the label's text in the initializer and through the setText method.
Other code idea tips.
Your initializer's arguments is a little confusing because you accept an arbitrary number of arguments, but only do something with the first one, and expect it to be a list of strings. A clear list of arguments is important.
Your use of apply to call the base class initializer is unnecessary. Change the code to simply qg.QTabWidget.__init__(self)
When creating a PyQt widget, I almost always prefer to allow a "parent" argument, even when I know the widget is going to be a toplevel widget. This is what all the built in Pyqt methods do, and feels like good practice to follow.
I also can't see the reason to store a list of tabs, with each one being a single element dictionary. I suspect you won't need to keep your own list of tabs and tab names. The QTabWidget can answer all questions about the contents.
If I were to bend this example code to my own preferences it would look like this.
from PyQt4 import QtCore as qc
from PyQt4 import QtGui as qg
class wqTabWidget(qg.QTabWidget):
def __init__(self, parent, tabNames):
qg.QTabWidget.__init__(self, parent)
self.createTabs(tabNames)
def createTabs(tabNames):
for name in tabNames:
tabWidget = qg.QWidget()
self.addTab(tabWidget, name)
if __name__ == '__main__':
app = qg.QApplication(sys.argv)
window = wqTabWidget(None, ['hi', 'there', 'and', 'stuff'])
window.show()
app.exec_()