How to interact with interface elements through different classes? [duplicate] - python

This question already has answers here:
Linking a qtDesigner .ui file to python/pyqt?
(12 answers)
Correct way to address Pyside Qt widgets from a .ui file via Python
(2 answers)
Closed 11 months ago.
For example, I want to change the text of a button by binding it to a function from another class. But I get an error on the line self.ui.pushButton.setText("OK"):
AttributeError: 'bool' object has no attribute 'ui'
Here is main.py code:
from PySide6.QtWidgets import QApplication, QWidget
import test_gui
class App(QWidget):
def __init__(self):
QWidget.__init__(self)
self.ui = test_gui.Ui_Form()
self.ui.setupUi(self)
self.ui.pushButton.clicked.connect(Second.func)
class Second(App):
def __init__(self):
App.__init__(self)
def func(self):
self.ui.pushButton.setText("OK")
if __name__ == "__main__":
app = QApplication([])
mw = App()
mw.show()
app.exec()
Here is test_gui.py code:
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'test_gui.ui'
##
## Created by: Qt User Interface Compiler version 6.2.4
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QPushButton, QSizePolicy, QWidget)
class Ui_Form(object):
def setupUi(self, Form):
if not Form.objectName():
Form.setObjectName(u"Form")
Form.resize(392, 279)
self.pushButton = QPushButton(Form)
self.pushButton.setObjectName(u"pushButton")
self.pushButton.setGeometry(QRect(120, 110, 75, 24))
self.retranslateUi(Form)
QMetaObject.connectSlotsByName(Form)
# setupUi
def retranslateUi(self, Form):
Form.setWindowTitle(QCoreApplication.translate("Form", u"Form", None))
self.pushButton.setText(QCoreApplication.translate("Form", u"PushButton", None))
# retranslateUi
Please tell me what is the problem?

Related

Browse media with PyQT6

I wanted to create a browsing media file with QT so I wrote that :
import sys
import random
import os
import time
from PyQt6 import QtCore, QtWidgets, QtGui
from PyQt6.QtWidgets import QLabel, QPushButton,QSizePolicy, QFileDialog,QHBoxLayout, QVBoxLayout, QSlider, QInputDialog, QMainWindow, QApplication
from PyQt6.QtGui import QPixmap, QShortcut, QKeySequence, QMovie
from PyQt6.QtCore import Qt,QUrl, QTimer, QSettings, QSize, QPoint
from PyQt6.QtMultimediaWidgets import QVideoWidget
from PyQt6.QtMultimedia import QMediaPlayer, QAudioOutput
# Subclass QMainWindow to customize your application's main window
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.posi = 0
#path
if (len( sys.argv ) > 1):
self.folderpath = sys.argv[1]
else:
self.folderpath = "your folder contaianing the files" #<============ DONT FORGET TO FINISH THE PATH WITH /
#pathlist
self.img_list = os.listdir(self.folderpath)
print(self.img_list)
self.setWindowTitle("My App")
self.mediaPlayer = QMediaPlayer(None)
self.videoWidget = QVideoWidget()
self.audio_output = QAudioOutput()
self.mediaPlayer.setVideoOutput(self.videoWidget)
self.mediaPlayer.setAudioOutput(self.audio_output)
self.audio_output.setVolume(50)
self.mediaPlayer.setLoops(-1)
self.mediaPlayer.setSource(QUrl(self.folderpath+self.img_list[0]))
self.mediaPlayer.play()
# Set the central widget of the Window.
self.setCentralWidget(self.videoWidget)
#shortcut
self.shortcut_right = QShortcut(QKeySequence("Right"),self)
self.shortcut_right.activated.connect(self.button_right_clicked)
def button_right_clicked(self, *args):#when navigate right
print("---->")
try:
self.img_list[self.posi+1]
except IndexError:
self.posi = 0
else:
self.posi = self.posi + 1
self.mediaPlayer.setSource(QUrl(self.folderpath+self.img_list[self.posi]))
self.mediaPlayer.play()
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
But sometimes when use the method "button_right_clicked" the program shutdown without any error or closing event. This method is used to navigate through the list of files in the source folder. I'm using only mp4 file for now.
The error comes from this line i presume : self.mediaPlayer.setSource(QUrl(self.folderpath+self.img_list[self.posi]))
Because when i try to set the same media (img_list[0]) file as source, instead of using index self.posi, it doesn't crash.
According to the documentation, it seems to be the approriate way of swapping between media.
Any idea how to solve this problem ?

Execute a function after closing a window (not a child window)?

I have in my application a button which after being clicked opens up another window (which is a separate python file).
I want to execute a function after this second window has been closed. Is there a way I can capture that window's 'closed' signal or something like that?
Here is my code: (the main window)
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPainter, QColor
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QVBoxLayout
from PyQt5.QtWidgets import QPushButton
import second_dialog # the second window I am importing
from sys import exit as sysExit
class Marker(QWidget):
def __init__(self):
QWidget.__init__(self)
self.resize(350, 250)
self.openbtn = QPushButton('open')
self.openbtn.clicked.connect(self.open_dialog)
self.label_1 = QtWidgets.QLabel()
self.label_1.setGeometry(QtCore.QRect(10, 20, 150, 31))
self.label_1.setObjectName("label_1")
self.label_1.setText("HEy")
HBox = QHBoxLayout()
HBox.addWidget(self.openbtn)
HBox.addWidget(self.label_1)
HBox.addStretch(1)
VBox = QVBoxLayout()
VBox.addLayout(HBox)
VBox.addStretch(1)
self.setLayout(VBox)
def open_dialog(self):
self.dialog = QtWidgets.QWidget()
self.box = second_dialog.Marker()
self.box.show()
def do_something(self):
self.label_1.setText("Closed")
def paintEvent(self, event):
p = QPainter(self)
p.fillRect(self.rect(), QColor(128, 128, 128, 128))
if __name__ == "__main__":
MainEventThred = QApplication([])
MainApp = Marker()
MainApp.show()
MainEventThred.exec()
Here is the code for the second window:
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPainter, QColor
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QVBoxLayout
from PyQt5.QtWidgets import QPushButton
import first_window
from sys import exit as sysExit
class Marker(QWidget):
def __init__(self):
QWidget.__init__(self)
self.resize(350, 250)
self.openbtn = QPushButton('close')
self.openbtn.clicked.connect(self.Close)
HBox = QHBoxLayout()
HBox.addWidget(self.openbtn)
HBox.addStretch(1)
VBox = QVBoxLayout()
VBox.addLayout(HBox)
VBox.addStretch(1)
self.setLayout(VBox)
def Close(self):
TEST_draggable.Marker.do_something(first_window.Marker)
self.close()
def paintEvent(self, event):
p = QPainter(self)
p.fillRect(self.rect(), QColor(128, 128, 128, 128))
if __name__ == "__main__":
MainEventThred = QApplication([])
MainApp = Marker()
MainApp.show()
MainEventThred.exec()
The code does not run and throws this error:
Traceback (most recent call last):
File "some/path/second_dialog.py", line 28, in Close
TEST_draggable.Marker.do_something(first_window.Marker)
File "some/path/first_window.py", line 39, in do_something
self.label_1.setText("clicked")
AttributeError: type object 'Marker' has no attribute 'label_1'
[1] 7552 abort (core dumped) /usr/local/bin/python3
How can I fix this? I've looked up a lot of forums suspecting circular imports as the culprit but I'm not sure. Please help.
The problem has nothing to do with imports, but with the fact that you're trying to run an instance method on a class.
The "culprit" is here:
TEST_draggable.Marker.do_something(first_window.Marker)
first_window.Marker will be used for the self argument in do_something, but since it is the class, it has no label_1 attribute (only the instances of that class have that attribute). I suggest you to do some research on how classes and instances work in general, and how to deal with them in Python.
The easiest solution is to create your own signal for the second window and connect that signal on the function that will "do_something". Instead of connecting to a new function, then, we subclass the closeEvent() and send the signal from there, so that we can capture the close even when the user clicks the dedicated button on the title bar. Note that if you want to change the behavior of close you can just override it and then call the base implementation (super().close()) instead of using another function name (which should not have a capitalized name, by the way, as they should only be used for classes and constants).
This is the second class; be aware that using identical names for different classes is a very bad idea.
from PyQt5.QtCore import pyqtSignal
class Marker(QWidget):
closed = pyqtSignal()
def __init__(self):
QWidget.__init__(self)
self.resize(350, 250)
self.openbtn = QPushButton('close')
self.openbtn.clicked.connect(self.close)
# ...
def closeEvent(self, event):
self.closed.emit()
Then, in the first:
class Marker(QWidget):
# ...
def open_dialog(self):
self.dialog = QtWidgets.QWidget()
self.box = second_dialog.Marker()
self.box.closed.connect(self.do_something)
self.box.show()

Icon not showing in QListWidgetItem

Icons are not showing in my QListWidgetItems.
Edit 2:
Turns out you can't use absoulte path. You must use relative path. But why is this the case?
Minimum reproducible example:
import json
import os
import sys
from math import floor
from PyQt5 import QtTest, QtGui
from PyQt5.QtDesigner import QFormBuilder
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QFrame, QGridLayout, QLabel, QMainWindow, QScrollArea, QWidget, QVBoxLayout, \
QListView, QListWidget, QListWidgetItem, QToolButton
from PyQt5.QtCore import QPoint, Qt, QIODevice, QFile
from PyQt5.Qt import QPixmap
class MainWindow(QMainWindow):
def __init__(self, *args, obj=None, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
#ListWidget
listWidget = QListWidget(self)
listWidget.setViewMode(QListWidget.IconMode)
listWidget.setFixedSize(500, 700)
dir = r'Players'
for filename in os.listdir(dir):
#Item
item = QListWidgetItem(QIcon('Players/Pogba.jpg'), '<Name>', listWidget)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.showMaximized()
app.exec_()
I followed the docs(https://doc.qt.io/qt-5/qlistwidgetitem.html), so why are they not appearing?
Edit:
It looks like it only happens when the image is outside the source code's folder. Why is this the case?

PyQt5 from apt install python3-pyqt5 [duplicate]

My code was created with PyQt4 and I want to convert it to PyQt5.
I have tried some scripts to convert the code; but, nothing changed except the name.
What do I need to change manually in order to make the code work with PyQt5?
Here is the first part of my code:
import sys
from pymaxwell import *
from numpy import *
from PyQt4 import QtGui, QtCore, uic
from PyQt4.QtGui import QMainWindow, QApplication
from PyQt4.QtCore import *
from PyQt4.phonon import Phonon
from ffmpy import FFmpeg
import os
import app_window_dark
import about
uifile = 'Ui/app_window_dark.ui'
aboutfile = 'Ui/about.ui'
Ui_MainWindow, QtBaseClass = uic.loadUiType(uifile)
Ui_Dialog= uic.loadUiType(uifile)
class About(QtGui.QMainWindow, about.Ui_Dialog):
def __init__(self, parent=None):
super(About, self).__init__()
QtGui.QMainWindow.__init__(self, parent)
Ui_Dialog.__init__(self)
self.setWindowModality(QtCore.Qt.ApplicationModal)
point = parent.rect().bottomRight()
global_point = parent.mapToGlobal(point)
self.move(global_point - QPoint(395, 265))
self.setupUi(self)
class MyApp(QtGui.QMainWindow, app_window_dark.Ui_MainWindow):
def __init__(self):
super(MyApp, self).__init__()
QtGui.QMainWindow.__init__(self)
self.ui = Ui_MainWindow.__init__(self)
self.setupUi(self)
self.about_btn.clicked.connect(self.popup)
#prev next
self.btn_next.clicked.connect(self.renderSet)
self.btn_prev.clicked.connect(self.renderSet)
and also this code:
if __name__ == "__main__":
app = QApplication(sys.argv)
#style = QApplication.setStyle('plastique')
window = MyApp()
window.setFixedSize(750, 320)
window.show()
sys.exit(app.exec_())
The main change from Qt4 to Qt5 and hence from PyQt4 to PyQt5 is the rearrangement of certain classes so that the Qt project is scalable and generates a smaller executable.
The QtGui library was divided into 2 submodules: QtGui and QtWidgets, in the second only the widgets, namely QMainWindow, QPushButton, etc. And that is the change you must make:
[...]
from PyQt5 import QtGui, QtCore, uic, QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtCore import *
[...]
Ui_MainWindow, QtBaseClass = uic.loadUiType(uifile)
Ui_Dialog= uic.loadUiType(uifile)
class About(QtWidgets.QMainWindow, about.Ui_Dialog):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.setWindowModality(QtCore.Qt.ApplicationModal)
point = parent.rect().bottomRight()
global_point = parent.mapToGlobal(point)
self.move(global_point - QPoint(395, 265))
class MyApp(QtWidgets.QMainWindow, app_window_dark.Ui_MainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.setupUi(self)
self.about_btn.clicked.connect(self.popup)
#prev next
self.btn_next.clicked.connect(self.renderSet)
self.btn_prev.clicked.connect(self.renderSet)
Note: Phonon does not exist in PyQt5, you must use QtMultimedia, an accurate solution you can find it in the following answer: Phonon class not present in PyQt5

How to align QPlainTextEdit to right?

I want to write a notepad in python with PyQt5 for persian language.
how can I align the thext in QPlainTextEdit to right?
this is my code:
from PyQt5.QtWidgets import QApplication, QMainWindow, QPlainTextEdit
from PyQt5.QtCore import Qt, QLocale
class TextBox(QPlainTextEdit):
def persian(self):
self.setFixedSize(640, 480)
self.setLayoutDirection(Qt.RightToLeft)
self.setLocale(QLocale(QLocale.Persian, QLocale.Iran))
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.GUI()
def GUI(self):
self.setWindowTitle("My title")
self.setFixedSize(640, 480)
self.text = TextBox(self)
self.text.persian()
app = QApplication([])
window = MainWindow()
window.show()
app.exec_()
You can use a QTextEdit instead of QPlainTextEdit and use setAlignment(Qt.AlignRight), e.g.
from PyQt5.QtWidgets import QTextEdit
from PyQt5.QtCore import Qt
class TextBox(QTextEdit):
def persian(self):
self.setFixedSize(640, 480)
self.setLayoutDirection(Qt.RightToLeft)
self.setLocale(QLocale(QLocale.Persian, QLocale.Iran))
# set text alignment to AlignRight
self.setAlignment(Qt.AlignRight)

Categories