QTimer persists after QMainWindow is closed - python-2.7

I'm having two QMainWindow subclasses, MyWindow and MyTimerWindow. The application initializes and shows a MyWindow instance which does nothing but initialize and show a MyTimerWindow instance. The MyTimerWindow creates a child object QTimer which fires the function printsomething every two seconds.
When I manually close the MyTimerWindow instance by clicking on the X in the titlebar, the printsomething function keeps being executed every two seconds. To my understanding the QTimer instance should be destroyed when I close its parent window. Can someone explain why the QTimer stays alive?
Here is the code:
import sys
from PyQt4 import QtCore, QtGui
class MyWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.setWindowTitle("main window")
self.centralwidget = QtGui.QWidget()
self.setCentralWidget(self.centralwidget)
timerwindow = MyTimerWindow(self)
timerwindow.show()
class MyTimerWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MyTimerWindow, self).__init__(parent)
self.setWindowTitle("timer window")
self.centralwidget = QtGui.QWidget()
self.setCentralWidget(self.centralwidget)
self.timer = QtCore.QTimer(self)
self.timer.setInterval(2000)
self.timer.timeout.connect(self.printsomething)
self.timer.start()
def printsomething(self):
print("something")
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MyWindow()
window.show()
returnvalue = app.exec_()
sys.exit(returnvalue)

Clicking the X in the titlebar will send a closeEvent to the window. If the window has a parent, it will be hidden, but not deleted.
To ensure that a parented window is deleted when closed, set the WA_DeleteOnClose flag:
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
This will also recursively delete all child objects of the window.

You can always override the close event.
class MyWindow(QtGui.QMainWindow):
def __init__(self, parent=None)
super().__init__(parent)
...
self.timerWindow = MyTimerWindow(self)
def closeEvent(self, event):
self.timerWindow.close()
super().__init__(parent)
Or you can always make your timer window a dialog box which is probably the best solution. I believe that the TimerWindow doesn't close automatically because it is a QMainWindow. A QDialog box should automatically be deleted on main window close.

Related

How to make QTabWidget clickable?

i searched about this topic and find some examples how to make qwidget clickable but just to print texts like this one
import sys
from PyQt4.QtGui import QWidget, QApplication
class MyWidget(QWidget):
def mousePressEvent(self, event):
print "clicked"
app = QApplication(sys.argv)
widget = MyWidget()
widget.show()
app.exec_()
what i need is it possible to make th QTabWidget clickable and when click on it we can use it like a button to open a file for example ?
What you should do is create a signal and output it as shown below:
class ClickableQTabWidget(QTabWidget):
clicked = pyqtSignal()
def mousePressEvent(self, event):
self.clicked.emit()
class Widget(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setLayout(QVBoxLayout())
self.cw = ClickableQTabWidget(self)
self.layout().addWidget(self.cw)
self.cw.clicked.connect(self.onClicked)
def onClicked(self):
print("clicked")
app = QApplication(sys.argv)
widget = Widget()
widget.show()
app.exec_()

Print will work across the class, but the action will not

When I click my button on the second window, it connects to the top class and successfully prints "yes", when I hit the stop button that binds to self.Hault, the timer stops and it prints. Is there something silly I am missing when I hit the button on the second window that would make it print, but not perform the action?
class Main(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.setupUi(self)
#timer commands
self.Start_2.clicked.connect(self.start_time)
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.Time)
self.Stop.clicked.connect(self.Hault)
self.window2 = None
def Hault(self):
self.timer.stop()
print ('yes')
class Form(QtGui.QDialog, Ui_Form):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
self.setupUi(self)
self.main1 = Main()
self.pop_up_pushButton.clicked.connect(self.main1.Hault)

Should I be passing GUI-entered variables between classes or restructuring program?

The user enters values using line edits on the MyWidget screen and then presses the Enter button. This opens the MyDialog screen on which data will be plotted when the Run button is pressed. How can I make the line edit data accessible to run in MyDialog for plotting? Or, is there a better way of doing this which wouldn't require passing variables between classes? My program is based on this answer.
from PyQt4 import QtCore, QtGui, uic
# Import Qt widgets
from matplotlib.backends.backend_qt4agg \
import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg \
import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
GUI_FILE = "Minimal_UI.ui" # GUI with line edit and 'enter' button
form_class = uic.loadUiType(GUI_FILE)[0]
class MyWidget(QtGui.QWidget, form_class):
def __init__(self, parent=None):
super(MyWidget, self).__init__(parent)
self.setupUi(self)
self.pushButton_Enter.clicked.connect(self.on_pushButton_clicked)
self.dialogTextBrowser = MyDialog(self)
#QtCore.pyqtSlot()
def on_pushButton_clicked(self):
# I'd like to be able to pass Temp_0 to the run method
self.Temp_0 = self.lineEdit_Temp_0.text()
self.dialogTextBrowser.exec_()
class MyDialog(QtGui.QDialog):
def __init__(self, parent=None):
super(MyDialog, self).__init__(parent)
self.fig = Figure()
self.canvas = FigureCanvas(self.fig)
self.toolbar = NavigationToolbar(self.canvas, self)
self.run_button = QtGui.QPushButton('Run')
self.run_button.clicked.connect(self.run)
self.stop_button = QtGui.QPushButton('Stop')
self.stop_button.clicked.connect(self.stop)
layout = QtGui.QVBoxLayout()
# Widgets are stacked in the order they are added
layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
layout.addWidget(self.run_button)
layout.addWidget(self.stop_button)
self.setLayout(layout)
def run(self):
# Create axes
ax = self.fig.add_subplot(111)
# Discard the old graphs
ax.hold(False)
# Plot data--I'd like to be able to use line edit data here
ax.plot([1, 2, 3, 4], '*-')
# Refresh canvas
self.canvas.draw()
def stop(self):
print 'Stop Pressed'
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName('MyWidget')
main = MyWidget()
main.show()
sys.exit(app.exec_())
MyDialog constructor has an attribute parent.
With the code bellow, you create an instance of MyDialog with MyWidget as a parent:
self.dialogTextBrowser = MyDialog(self)
Two ways for a widget to access data from it's parent:
Use the parent attribute in the __init__ function
self.lineEditData=parent.lineEdit.text()
Use the parent() method anywhere
def run(self):
self.lineEditData=self.parent().lineEdit.text()
I say it depends on how your suppose to use the application. If your suppose to fill the lineEdit once click and get a plot, I would use the parent attribute or directly pass the data in the __init__ function.
But if the user can go back to the lineEdit, change something, and click "run" again, then you should use the parent() method in run.

How to change a content in a window in PySide?

I want to click on a menubar "Tools" menu to change my window content completely. How do I do this with PySide? Should I call QAction and set new widget as a central one with a parent of an old window? I'm beginner in python and english too. So far I've created only one-window application.
Firstly, I would define each tool within its own subclass of a QWidget. Secondly, I would add an instance of each tool widget thus created to the layout of the central widget of the main window. Finally, I would add actions to the menuBar and connect them to methods to show and hide the tools as desired.
Below is an example to show how this can be done with 2 different tools:
from PySide import QtGui
import sys
class myApplication(QtGui.QMainWindow):
def __init__(self, parent=None):
super(myApplication, self).__init__(parent)
self.setWindowTitle('No Tool is Selected')
#---- create instance of each tool widget ----
self.tool1 = Tool1(self)
self.tool2 = Tool2(self)
#---- layout for central widget ----
centralWidget = QtGui.QWidget()
centralLayout = QtGui.QGridLayout()
centralLayout.addWidget(self.tool1, 0, 0)
centralLayout.addWidget(self.tool2, 1, 0)
centralWidget.setLayout(centralLayout)
self.setCentralWidget(centralWidget)
#---- set the menu bar ----
contentMenu = self.menuBar().addMenu(("Tools"))
contentMenu.addAction('show Tool 1', self.show_Tool1)
contentMenu.addAction('show Tool 2', self.show_Tool2)
contentMenu.addAction('show All', self.show_All)
def show_Tool1(self):
self.tool1.show()
self.tool2.hide()
self.setWindowTitle('Tool #1 is Selected')
def show_Tool2(self):
self.tool1.hide()
self.tool2.show()
self.setWindowTitle('Tool #2 is Selected')
def show_All(self):
self.tool1.show()
self.tool2.show()
self.setWindowTitle('All Tools are Selected')
class Tool1(QtGui.QWidget):
def __init__(self, parent=None):
super(Tool1, self).__init__(parent)
layout = QtGui.QGridLayout()
layout.addWidget(QtGui.QPushButton('Tool #1'))
self.setLayout(layout)
self.hide()
class Tool2(QtGui.QWidget):
def __init__(self, parent=None):
super(Tool2, self).__init__(parent)
layout = QtGui.QGridLayout()
layout.addWidget(QtGui.QTextEdit('Tool #2'))
self.setLayout(layout)
self.hide()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
instance = myApplication()
instance.show()
sys.exit(app.exec_())
Which results in:

Mouse events in PyQt5 and PyQt4

I used to have an application in PyQt5, where user could move QGroupBox widget, by pressing mouse button and simply move it. In PyQt5 it works perfectly, but I had to refuse PyQt5 for some reasons and use PyQt4 instead of it. But now I can move my QgroupBox widget only after double click. I use the same piece of code, but in PyQt5 it worked after one click and now only after second one (after first click the whole application's window starts to move). What should I add/edit in order to reach the same result like in PyQt5?
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class WidgetPattern(QGroupBox):
def __init__(self, name, parent=None):
super(WidgetPattern, self).__init__(parent=parent)
self.layout = QVBoxLayout(self)
self._offset = 0
self.widgetLength = 280
self.name = QLabel(parent=self)
self.name.setText(name)
self.name.adjustSize()
self.name.move(self.widgetLength / 2 - self.name.width() / 2, 5)
self.close_button = QToolButton(parent=self)
self.close_button.resize(24, 24)
self.close_button.setAutoRaise(True)
self.close_button.move(self.widgetLength - self.close_button.width(), 0)
self.close_button.setIcon(QIcon.fromTheme("application-exit"))
self.setFixedSize(280, 60)
def mousePressEvent(self, event):
self._offset = event.pos()
def mouseMoveEvent(self, event):
self.move(
QGroupBox.mapToParent(
self,
event.pos() -
self._offset))
class ConcertGUI(QWidget):
def __init__(self, parent=None):
super(ConcertGUI, self).__init__(parent)
widget=WidgetPattern("test")
self._main_layout = QVBoxLayout()
self._main_layout.addWidget(widget, 0)
self.setLayout(self._main_layout)
self.resize(1024, 500)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
gui = ConcertGUI()
gui.show()
sys.exit(app.exec_())