This question already has an answer here:
How to open a window with a click of a button from another window using PyQt?
(1 answer)
Closed 3 years ago.
I want to create a new window when a button is clicked. I will later have windows be created dynamically depending on inputted data. But I want to start simple first.
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QPushButton, QGridLayout, QWidget
class MyWindow(QtWidgets.QMainWindow, QPushButton):
def __init__(self):
super(MyWindow, self).__init__()
centralWidget = QWidget()
self.setCentralWidget(centralWidget)
self.setWindowTitle("ASSET")
self.Button = QPushButton('Action',self)
self.Button.clicked.connect(self.Action)
self.layout = QGridLayout(centralWidget)
self.layout.addWidget(self.Button)
def Action(self):
pass
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())
You can create another QMainWindow() and when the button is clicked, activate the show() method
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QPushButton, QGridLayout, QWidget, QLabel
class NewWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(NewWindow, self).__init__(parent)
self.label = QLabel('New Window!')
centralWidget = QWidget()
self.setCentralWidget(centralWidget)
self.layout = QGridLayout(centralWidget)
self.layout.addWidget(self.label)
class MyWindow(QtWidgets.QMainWindow, QPushButton):
def __init__(self):
super(MyWindow, self).__init__()
centralWidget = QWidget()
self.setCentralWidget(centralWidget)
self.setWindowTitle("ASSET")
self.Button = QPushButton('Action',self)
self.Button.clicked.connect(self.Action)
self.layout = QGridLayout(centralWidget)
self.layout.addWidget(self.Button)
self.new_window = NewWindow(self)
def Action(self):
self.new_window.show()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())
Related
what I am trying to do with a python script: Use a pytest test method to print a text line to a label in the pyqt GUI.
When running the main python file, the GUI starts and a click on the "test" button runs the test without blocking the GUI (see full code example below). But I have no clue how to proceed now.
Code:
import sys
import pytest
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QWidget
class Window(QtWidgets.QMainWindow):
signal_start_background_job = QtCore.pyqtSignal()
def __init__(self):
super(Window, self).__init__()
layout = QVBoxLayout()
self.button = QtWidgets.QPushButton("test", self)
self.label = QtWidgets.QLabel("console output")
layout.addWidget(self.button)
layout.addWidget(self.label)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
self.worker = WorkerObject()
self.thread = QtCore.QThread()
self.worker.moveToThread(self.thread)
self.signal_start_background_job.connect(self.worker.background_job)
self.button.clicked.connect(self.start_background_job)
def start_background_job(self):
self.thread.start()
self.signal_start_background_job.emit()
class WorkerObject(QtCore.QObject):
#QtCore.pyqtSlot()
def background_job(self):
pytest.main(["-s", "-k test_something"])
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
def test_something():
print("unit test some stuff")
assert 0 == 0
Instead of using pytest directly you could use QProcess to launch it and then capture the output:
import os
import sys
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QWidget
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
class Window(QtWidgets.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.button = QtWidgets.QPushButton("test", self)
self.label = QtWidgets.QLabel("console output")
self.textedit = QtWidgets.QTextEdit(readOnly=True)
widget = QWidget()
layout = QVBoxLayout(widget)
layout.addWidget(self.button)
layout.addWidget(self.label)
layout.addWidget(self.textedit)
self.setCentralWidget(widget)
self.process = QtCore.QProcess()
self.process.setProgram(sys.executable)
self.process.readyReadStandardError.connect(self.on_readyReadStandardError)
self.process.readyReadStandardOutput.connect(self.on_readyReadStandardOutput)
self.button.clicked.connect(self.on_clicked)
#QtCore.pyqtSlot()
def on_clicked(self):
self.process.setWorkingDirectory(CURRENT_DIR)
self.process.setArguments(["-m", "pytest", "-s", "-k", "test_something"])
self.process.start()
#QtCore.pyqtSlot()
def on_readyReadStandardError(self):
err = self.process.readAllStandardError().data().decode()
self.textedit.append(err)
#QtCore.pyqtSlot()
def on_readyReadStandardOutput(self):
out = self.process.readAllStandardOutput().data().decode()
self.textedit.append(out)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
I'm thinking you need to check out sys.stdout, and route that to an io object that you can route to the label in your widget. Then I would set a timer and every 0.1 seconds or so set the text of your label to that object. Alternatively you can implement a widget that grabs the stdout text in qt, example here: https://stackoverflow.com/a/1220002/6615517 I haven't tried it but the other answers to that question should help. You'll probably want to clear the label on each test to prevent it from getting too long.
Is it possible to run a custom method on clicking the ClearButton in a QLineEdit?
For instance i have a ClearButton inside a QCombobox and i want to set a default-index on clicking the ClearButton in this ComboBox.
I have already tried to subclass the 'clear()' slot of the QLineEdit, but without success.
qtawesome
import sys
from PyQt5.QtWidgets import (QLineEdit, QApplication, QWidget, QVBoxLayout)
import qtawesome as qt
class Widget(QWidget):
def __init__(self, parent=None):
super(QWidget, self).__init__(parent)
self.flag = 0
self.layout = QVBoxLayout()
self.line_edit = QLineEdit()
self.line_edit.setClearButtonEnabled(False)
self.line_edit.textChanged.connect(self._on_line_edit_text_changed)
self.clear_icon = qt.icon('mdi.delete-circle-outline', color='gray', color_active='black')
self.clear_action = None
self.layout.addWidget(self.line_edit)
self.setLayout(self.layout)
def _on_line_edit_text_changed(self):
if self.line_edit and self.line_edit.text():
if not self.clear_action:
self.clear_action = self.line_edit.addAction(self.clear_icon, QLineEdit.TrailingPosition)
self.clear_action.triggered.connect(self._on_clear_clicked)
elif self.clear_action and self.line_edit and not self.line_edit.text():
self.line_edit.removeAction(self.clear_action)
self.clear_action = None
def _on_clear_clicked(self):
self.line_edit.clear()
if __name__ == "__main__":
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
I read that it is possible to use a simple QWidget as Layout for a page of a QTabWidget, so that I can design the tab page the way I want it.
How do I implement that?
One of the functionalities of a QWidget is to be a container so it is only necessary to add it in each tab:
from PyQt5 import QtCore, QtGui, QtWidgets, QtPrintSupport
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.tab_widget = QtWidgets.QTabWidget()
self.setCentralWidget(self.tab_widget)
page1 = QtWidgets.QWidget()
page2 = QtWidgets.QWidget()
for page, title in ((page1, "Page1"), (page2, "Page2")):
self.tab_widget.addTab(page, title)
lay1 = QtWidgets.QVBoxLayout(page1)
for i in range(3):
lay1.addWidget(
QtWidgets.QLabel(f"label{i}", alignment=QtCore.Qt.AlignCenter)
)
lay1.addStretch()
lay2 = QtWidgets.QVBoxLayout(page2)
for i in range(4):
lay2.addWidget(QtWidgets.QPushButton(f"button {i}"))
lay2.addStretch()
self.resize(640, 480)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec())
I'm using PyQt5, QMainWindow and I want to change default position of toolbar to the right. How can I do it?
User can carry toolbar to the edges of the window using mouse, but how can I do it using program?
def initUI(self):
self.toolbar = self.addToolBar('Example')
You have to use the addToolBar method as shown below:
import sys
from PyQt5 import QtCore, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.initUI()
def initUI(self):
self.toolbar = QtWidgets.QToolBar("Example")
self.addToolBar(QtCore.Qt.RightToolBarArea, self.toolbar)
self.toolbar.addAction("action 1")
self.toolbar.addAction("action 2")
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
In order to track progress, this is the third question about practicing with different classes in PyQt5 .Here are the links to my previous questions:opening a new window, Open a file from main window to a new window in PyQt5 (in different files).
I'm trying to work with two classes, one with one button and when it's pressed it will load a file and show the text in a QTextEdit in other class.
In the first questions I was suggested that as an alternative to work with more classes, they can inherit from QMainWindow so I looked for more info for doing this: PyQt class inheritance
The second question code did worked but it would show both windows at the same time, so this question: PyQt: How to hide QMainWindow guided me to write this code (I attatch this here because it's a little bit different from the one in the link, plus I apply what it says in the answer):
import sys, os
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton
class Dialog_02(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Dialog_02, self).__init__(parent, QtCore.Qt.Window)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
myBoxLayout = QVBoxLayout()
Button_02 = QPushButton ("Show Dialog 01")
myBoxLayout.addWidget(Button_02)
self.setLayout(myBoxLayout)
self.setWindowTitle('Dialog 02')
Button_02.clicked.connect(self.closeAndReturn)
def closeAndReturn(self):
self.close()
self.parent().show()
class Dialog_01(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Dialog_01, self).__init__()
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
myBoxLayout = QVBoxLayout()
Button_01 = QPushButton ("Show Dialog 02")
myBoxLayout.addWidget(Button_01)
self.setLayout(myBoxLayout)
self.setWindowTitle('Dialog 01')
Button_01.clicked.connect(self.callAnotherQMainWindow)
def callAnotherQMainWindow(self):
self.hide()
self.dialog_02 = Dialog_02(self)
self.dialog_02.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
dialog_1 = Dialog_01()
dialog_1.show()
sys.exit(app.exec_())
In this code I'm not inheriting, but it works fine.
The issue is that when I try to follow the same syntax in the original question code, it won't run, I'm not sure I'm getting inheritances fine.
import sys
import os
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtWidgets import QPushButton, QVBoxLayout, QTextEdit, QHBoxLayout, QLabel, QMainWindow, QAction, QFileDialog
class SecondWindow(QWidget):
def __init__(self, Window):
super(SecondWindow, self).__init__(parent, QtCore.Qt.Window)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.text = QTextEdit(self)
self.btn_return= QPushButton("Return")
self.init_ui()
def init_ui(self):
v_layout = QVBoxLayout(self)
v_layout.addWidget(self.text)
v_layout.addWidget(self.btn_return)
self.setLayout(v_layout)
self.setWindowTitle('Opened Text')
self.btn_return.clicked.connect(self.closeAndReturn)
def closeAndReturn(self):
self.close()
self.parent().show()
class Window(QMainWindow):
textChanged = QtCore.pyqtSignal(str)
def __init__(self, *args):
super(Window, self).__init__()
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.img = QLabel()
self.load_file= QPushButton('Load')
self.width = 400
self.height = 150
self.init_ui()
def init_ui(self):
self.img.setPixmap(QtGui.QPixmap("someimage.png"))
h_layout = QHBoxLayout()
v_layout = QVBoxLayout()
h_final = QHBoxLayout()
h_layout.addWidget(self.img)
v_layout.addWidget(self.load_file)
h_final.addLayout(h_layout)
h_final.addLayout(v_layout)
self.load_file.clicked.connect(self.loadafile)
self.setLayout(h_final)
self.setWindowTitle('Main Window')
self.setGeometry(600,150,self.width,self.height)
#QtCore.pyqtSlot()
def loadafile(self):
filename = QFileDialog.getOpenFileName(self, 'Open File', os.getenv('HOME'))
with open(filename[0], 'r') as f:
file_text = f.read()
self.textChanged.emit(file_text)
self.hide()
self.dialog_02 = SecondWindow(self)
self.dialog_02.show()
def main():
app = QApplication(sys.argv)
main = Window()
s = SecondWindow(main)
main.textChanged.connect(s.text.append)
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
You are coupling many classes: What happens if at a moment SecondWindow does not have a parent? Well, your code will have problems and you will have to modify it a lot so that it works correctly. So first it is to design the behavior of each class, for example SecondWindow has to warn the other windows that it was clicked, it has to have a method that updates the text. Similarly, Window must notify that there is new text available.
On the other hand QMainWindow already has a predefined layout so you must create a centralwidget where you place the other widgets.
import os
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class SecondWindow(QtWidgets.QWidget):
closed = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(SecondWindow, self).__init__(parent, QtCore.Qt.Window)
self.text = QtWidgets.QTextEdit()
self.btn_return= QtWidgets.QPushButton("Return")
self.init_ui()
def init_ui(self):
v_layout = QtWidgets.QVBoxLayout(self)
v_layout.addWidget(self.text)
v_layout.addWidget(self.btn_return)
self.setWindowTitle('Opened Text')
self.btn_return.clicked.connect(self.close)
self.btn_return.clicked.connect(self.closed)
#QtCore.pyqtSlot(str)
def update_text(self, text):
self.text.setText(text)
self.show()
class Window(QtWidgets.QMainWindow):
textChanged = QtCore.pyqtSignal(str)
def __init__(self, *args):
super(Window, self).__init__()
self.img = QtWidgets.QLabel()
self.load_file= QtWidgets.QPushButton('Load')
self.width = 400
self.height = 150
self.init_ui()
def init_ui(self):
self.img.setPixmap(QtGui.QPixmap("someimage.png"))
self.load_file.clicked.connect(self.loadafile)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
h_layout = QtWidgets.QHBoxLayout(central_widget)
h_layout.addWidget(self.img)
h_layout.addWidget(self.load_file)
self.setWindowTitle('Main Window')
self.setGeometry(600,150,self.width,self.height)
#QtCore.pyqtSlot()
def loadafile(self):
filename, _ = QtWidgets.QFileDialog.getOpenFileName(self, 'Open File', os.getenv('HOME'))
if filename:
with open(filename, 'r') as f:
file_text = f.read()
self.textChanged.emit(file_text)
self.close()
def main():
app = QtWidgets.QApplication(sys.argv)
main = Window()
s = SecondWindow()
main.textChanged.connect(s.update_text)
s.closed.connect(main.show)
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()