I am trying to create an application with a table in it to display rows of data. When more data arrives, I'd like to add a row and enter the data. However, I'm stuck at adding the row. Also, my own CreateTable class that inherits QtWidgets.QTableWidget works, but I don't understand why the line
self = QTableWidget(win)
is required. I've tried to keep the code as simple as possible just now until I get round having the table as an object with custom functions (add_row, delete_row...). Here is my code:
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidget, QTableWidgetItem
import sys
class CreateTable(QTableWidget):
def __init__(self, win):
super().__init__()
# Doesn't display table without the next line. I don't understand why it is required.
self = QTableWidget(win)
#
self.setGeometry(50, 50, 1820, 920)
self.setRowCount(10)
self.setColumnCount(10)
def add_row(self):
rowcount = self.rowCount()
self.insertRow(rowcount)
class MainWindow(QMainWindow):
def __init__(self):
"""MainWindow constructor."""
super().__init__()
# Main UI code
self.setGeometry(0, 0, 1920, 1040)
self.setWindowTitle("Order Manager")
table = CreateTable(self)
table.add_row()
# Main code
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
This code opens the window and displays a table with 10 rows, but doesn't add the row to make 11 rows. I am quite new to OOP and PyQt5, but am trying to learn more!
New working code:
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidget, QTableWidgetItem
import sys
class MainWindow(QMainWindow):
def __init__(self):
"""MainWindow constructor."""
super().__init__()
# Main UI code
self.setGeometry(0, 0, 1920, 1040)
self.setWindowTitle("Order Manager")
self.table = CreateTable(self)
self.table.add_row()
class CreateTable(QTableWidget):
def __init__(self, win):
super().__init__(win)
self.setGeometry(50, 55, 1820, 920)
self.setRowCount(10)
self.setColumnCount(10)
def add_row(self):
rowcount = self.rowCount()
self.insertRow(rowcount)
# Main code
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
Related
I wanted to try and see if I could create a class for the QPushButton widget in PyQt5 to save some lines. But once I create to create an instance of the Button class, it doesn't appear anywhere on the win instance of the Window class.
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Nested Layouts")
self.resize(800, 200)
self.show()
class Button(QPushButton):
def __init__(self, btn_parent, btn_text, btn_width, btn_height, btn_xCor, btn_yCor):
super().__init__()
self.btn_parent = btn_parent
self.btn_text = btn_text
self.btn_width = btn_width
self.btn_height = btn_height
self.btn_xCor = btn_xCor
self.btn_yCor = btn_yCor
self.setText(self.btn_text)
self.resize(btn_width, btn_height)
self.move(btn_xCor, btn_yCor)
app = QApplication(sys.argv)
win = Window()
button = Window.Button(btn_parent=win, btn_text="This won't work", btn_width=10, btn_height=10, btn_xCor=10, btn_yCor=10)
app.exec()
I even tried to make it like this, but the results are the same:
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Nested Layouts")
self.resize(800, 200)
self.show()
class Button(QPushButton):
def __init__(self, btn_parent, btn_text, btn_width, btn_height, btn_xCor, btn_yCor):
super().__init__()
self.btn_parent = btn_parent
self.btn_text = btn_text
self.btn_width = btn_width
self.btn_height = btn_height
self.btn_xCor = btn_xCor
self.btn_yCor = btn_yCor
self.setText(self.btn_text)
self.resize(btn_width, btn_height)
self.move(btn_xCor, btn_yCor)
app = QApplication(sys.argv)
win = Window()
button = Button(btn_parent=win, btn_text="This won't work", btn_width=10, btn_height=10, btn_xCor=10, btn_yCor=10)
app.exec()
Keep in mind that I'm kind of new to OOP(and Python and programming in general), so I might have a misunderstanding about how OOP works.
How can I fix this code so that the button shows on the win instance?
There are lots of widgets in the original code and that is why I need to open the file in the main window. Therefore, I need to pass a dataframe (data_df) that comes from a csv file open in the main menu (main class) to 'MyApp' class. I will use the dataframe (input_df) to perform calculations down the road.
How to pass the data from main class to MyApp class?
# Import dependencies
from PyQt5.QtWidgets import (QWidget, QApplication, QTableWidget, QTableWidgetItem, QHBoxLayout, QVBoxLayout, QHeaderView, QPushButton, QCheckBox,
QLabel, QFileDialog, QMainWindow, QAction, QLineEdit, QMessageBox, QComboBox, QSizePolicy)
from PyQt5.Qt import Qt, QPen, QFont
from PyQt5.QtGui import *
from PyQt5.QtChart import QChart, QChartView, QLineSeries, QCategoryAxis
import sys
import pandas as pd
import math
import csv
# Creates a QApplication instance
class MyApp(QWidget):
def __init__(self):
super().__init__()
# Creates layout object
self.layout = QHBoxLayout()
# Create push buttons
self.buttonCalc = QPushButton('Calculate')
self.layout.addWidget(self.buttonCalc)
# Connect button to function
self.buttonCalc.clicked.connect(self.calculate)
def displayInfo(self):
self.show()
# Create a Model to handle the calculator's operation
def calculate(self):
# get dataframe
input_df = df
# Create a subclass of QMainWindow to setup the main GUI
class MainWindow(QMainWindow):
def __init__(self, w):
super().__init__()
self.setWindowTitle('My code')
# for icon, uncomment line below
#self.setWindowIcon(QIcon(r'c:\image.png'))
self.resize(1200, 1200)
self.myApp = MyApp()
self.menuBar = self.menuBar()
self.fileMenu = self.menuBar.addMenu('File')
# import data
importAction = QAction('Open csv File', self)
importAction.setShortcut('Ctrl+O')
importAction.triggered.connect(self.openSeries)
# exit action
exitAction = QAction('Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.triggered.connect(lambda: app.quit())
self.fileMenu.addAction(importAction)
self.fileMenu.addAction(exitAction)
self.setCentralWidget(w)
def openSeries(self):
self.filePath = QFileDialog.getOpenFileName(self, 'Open data series csv file', 'C:\', 'CSV(*.csv)')
if self.filePath != ('', ''):
file_data = self.filePath[0]
data_df = pd.read_csv(file_data, encoding='ISO-8859-1')
# I need to pass this dataframe to MyApp class
return data_df
def passInformation(self):
self.myApp.input_df
if __name__ =='__main__':
app = QApplication(sys.argv)
w = MyApp()
window = MainWindow(w)
window.show()
try:
sys.exit(app.exec())
except SystemExit:
print('Closing window...')
You can pass the data from one another through the __init__ method using something like this on your main window class:
class MainWindow(QtWidgets.QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.init_ui()
def goToOtherWindow(self, variable):
self.window = OtherWindow(variable)
self.window.show()
self.close()
On OtherWindow class:
class OtherWindow(QtWidgets.QWidget):
def __init__(self, variable, parent=None):
super(OtherWindow, self).__init__(parent)
self.variable = variable
self.init_ui()
Of course, you have to adapt this function to your specific case.
Trying to animate a line growing from nothing to a (0,0) to (200, 200) line with PyQt5 and using QPropertyAnimation. I already read a lot of documentation about Qt and tried several samples, but I just cannot get this to work. This is the code I have now:
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
from PyQt5.QtGui import QPainter, QPixmap, QPainterPath
from PyQt5.QtCore import QObject, QPointF, QPropertyAnimation, pyqtProperty
from PyQt5.QtCore import QLineF
import sys
class Sample(QWidget):
l1 = QLineF(QPointF(), QPointF())
def __init__(self):
super().__init__()
self.initView()
self.initAnimation()
def initView(self):
self.show()
def initAnimation(self):
self.anim = QPropertyAnimation(self.l1, b'geometry')
self.anim.setDuration(7000)
self.anim.setStartValue(QPointF(0, 0))
self.anim.setEndValue(QPointF(200, 200))
self.anim.start()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Sample()
sys.exit(app.exec_())
Not posting all previous attemps, each one fails with a different error. I got a fade out animation on a widget to work, and a picture following a path, but I can seem to make a simple line drawing work. I was hoping to achieve something like this:
Codepen example
Qt documentation is huge and it seems there are several ways to achieve this, painter and timer, animation, variant animation, but I am not very familiar with C++ and the translation to Python is not always easy. Also samples are not that easy to find.
Am I missing something obvious?
Thanks!
For the record, this is what I achieved so far but as soon as I un-comment the QPropertyAnimation creation, app does not launch. Anyway I was still far from the result in the accepted answer.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class MyLine(QGraphicsLineItem, QObject):
def __init__(self):
super().__init__()
def _set_start(self, point):
self.setLine(point.x(), point.y(), self.line().p2().x(), self.line().p2().y())
def _set_end(self, point):
self.setLine(self.line().p1().x(), self.line().p1().y(), point.x(), point.y())
start = pyqtProperty(QPointF, fset=_set_start)
end = pyqtProperty(QPointF, fset=_set_end)
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
hbox = QHBoxLayout(self)
self.button = QPushButton("Start", self)
self.button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
hbox.addWidget(self.button)
hbox.addSpacing(40)
self.line = MyLine()
self.line.setLine(0, 0, 10, 10)
scene = QGraphicsScene()
scene.addItem(self.line)
view = QGraphicsView(scene)
hbox.addWidget(view)
self.anim = QPropertyAnimation(self.line, b"end") # crash without error here
# self.anim.setDuration(2500)
# self.anim.setLoopCount(1)
# self.anim.setStartValue(QPointF(10, 10))
# self.anim.setEndValue(QPointF(200, 200))
# self.button.clicked.connect(self.anim.start)
self.setGeometry(300, 300, 380, 250)
self.setWindowTitle('Color anim')
self.show()
if __name__ == "__main__":
app = QApplication([])
ex = Example()
ex.show()
app.exec_()
You have to use QGraphicsView, QGraphicsScene with QGraphicsLineItem as I show below:
from PyQt5 import QtCore, QtGui, QtWidgets
class LineAnimation(QtCore.QObject):
def __init__(self, parent=None):
super(LineAnimation, self).__init__(parent)
self.m_line = QtCore.QLineF()
self.m_item = QtWidgets.QGraphicsLineItem()
self.m_item.setLine(self.m_line)
self.m_item.setPen(
QtGui.QPen(
QtGui.QColor("salmon"),
10,
QtCore.Qt.SolidLine,
QtCore.Qt.SquareCap,
QtCore.Qt.RoundJoin,
)
)
self.m_animation = QtCore.QPropertyAnimation(
self,
b"p2",
parent=self,
startValue=QtCore.QPointF(0, 0),
endValue=QtCore.QPointF(200, 200),
duration=5 * 1000,
)
self.m_animation.start()
def p1(self):
return self.m_line.p1()
def setP1(self, p1):
self.m_line.setP1(p1)
self.m_item.setLine(self.m_line)
def p2(self):
return self.m_line.p2()
def setP2(self, p2):
self.m_line.setP2(p2)
self.m_item.setLine(self.m_line)
p1 = QtCore.pyqtProperty(QtCore.QPointF, fget=p1, fset=setP1)
p2 = QtCore.pyqtProperty(QtCore.QPointF, fget=p2, fset=setP2)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
scene = QtWidgets.QGraphicsScene(self)
view = QtWidgets.QGraphicsView(
scene, alignment=QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop
)
self.setCentralWidget(view)
line_animation = LineAnimation(self)
scene.addItem(line_animation.m_item)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
This question already has an answer here:
How to fix error in my pyqt programm (first argument of unbound method must have type 'QDialog') ?
(1 answer)
Closed 3 years ago.
I'm trying to build a GUI app using PyQt5 and Python 3.7 and I've decided to break the code in different modules. When i try to import a function that creates an instance of a custom widget, an error related to 'sis'. What I read is that 'sis' is a way of encapsulation C/C++ code to be run in python. But how can I work with that?
This is the code that runs the app:
import sys
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setGeometry(10,35,1500,800)
self.setWindowTitle("Cotizador TuCheff")
#self.setWindowIcon(QtGui.QIcon(''))
mainWindow(self)
def mainWindow(self):
from PyQt5 import QtCore, QtGui, QtWidgets
from Pages.Quote import quote
barMenu = QtWidgets.QTabWidget(self)
tab1 = QtWidgets.QWidget()
quoteLayout = QtWidgets.QVBoxLayout()
quoteGenerator = quote.makeQuoteWindow()
quoteLayout.addWidget(quoteGenerator)
tab1.setLayout(quoteLayout)
barMenu.addTab(tab1, "&Nueva CotizaciĆ³n")
self.setCentralWidget(barMenu)
if __name__ == "__main__":
app = QApplication([])
window = MainWindow()
window.show()
app.exec_()
And file, where I try to get a custom widget, is:
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QApplication
import sys
def makeQuoteWindow():
quoteWindow = QuoteWindow
quoteWindow.create()
#app = QApplication([])
#window = quoteWindow()
#window.show()
#status = app.exec_()
#sys.exit(status)
class QuoteWindow(QtWidgets.QWidget):
def __init__(self):
super(QuoteWindow, self).__init__()
def create(self):
mainWidget = QtWidgets.QWidget()
vLayout1 = QtWidgets.QVBoxLayout()
#=======------------------------ UPPER SIDE -------------------
hLayout1 = QtWidgets.QHBoxLayout()
##A LOT OF WIDGETS AND LAYOUTS
hLayout2 = QtWidgets.QHBoxLayout()
#display content
vLayout1.addLayout(hLayout1)
vLayout1.addLayout(hLayout2)
hLayout2.addItem(vSpacer1)
mainWidget.setLayout(vLayout1)
return mainWidget
if __name__ == "__main__":
makeQuoteWindow()
The error is:
TypeError: create(self, window: sip.voidptr = 0, initializeWindow: bool = True, destroyOldWindow: bool = True): first argument of unbound method must have type 'QWidget'
Try it:
main.py
import sys
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtWidgets import QApplication, QMainWindow
# from Pages.Quote import quote
from Quote import QuoteWindow
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setGeometry(10,35,1500,800)
self.setWindowTitle("Cotizador TuCheff")
self.setWindowIcon(QtGui.QIcon('im.png'))
# mainWindow(self)
self.mainWindow()
def mainWindow(self):
# from Pages.Quote import quote
self.quoteWindow = QuoteWindow() # +++
barMenu = QtWidgets.QTabWidget(self)
tab1 = QtWidgets.QWidget()
quoteLayout = QtWidgets.QVBoxLayout()
# quoteGenerator = quote.makeQuoteWindow()
# quoteLayout.addWidget(quoteGenerator)
quoteLayout.addWidget(self.quoteWindow) # +++
tab1.setLayout(quoteLayout)
barMenu.addTab(tab1, "&Nueva CotizaciĆ³n")
self.setCentralWidget(barMenu)
if __name__ == "__main__":
app = QApplication([])
window = MainWindow()
window.show()
app.exec_()
Quote.py
from PyQt5 import QtCore, QtWidgets, QtGui
class QuoteWindow(QtWidgets.QWidget):
def __init__(self):
super(QuoteWindow, self).__init__()
def create(self):
mainWidget = QtWidgets.QWidget()
vLayout1 = QtWidgets.QVBoxLayout()
#=======------------------------ UPPER SIDE -------------------
hLayout1 = QtWidgets.QHBoxLayout()
##A LOT OF WIDGETS AND LAYOUTS
hLayout2 = QtWidgets.QHBoxLayout()
#display content
vLayout1.addLayout(hLayout1)
vLayout1.addLayout(hLayout2)
hLayout2.addItem(vSpacer1)
mainWidget.setLayout(vLayout1)
return mainWidget
I have build a GUI with PyQt5 and I now want to integrate it with another python program. I have previously done this by placing GUI code written in TKinter in a separate thread. I want to know how to integrate this PyQt GUI into my other code the best way.
My other program has 2 threads monitoring rotary encoders and the main thread works on a RFID reader + some database communication.
Do the PyQt GUI have to be the main thread of the program?
Here is the PyQt gui:
from PyQt5 import QtGui
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QTableWidget, QTableWidgetItem, QVBoxLayout, QLabel
from PyQt5.QtGui import QPixmap
import sys
class Reminder():
def __init__(self):
self.activity = 'activity' # instance variable unique to each instance
self.time = 0000
self.day = 'day'
self.multiple_days = False
class Window(QWidget):
def __init__(self):
super().__init__()
self.titel = "GUI for Andreas"
self.top = 150
self.left = 150
self.width = 500
self.height = 500
self.setWindowIcon(QtGui.QIcon("calender.png"))
self.InitWindow()
def InitWindow(self):
self.setWindowTitle(self.titel)
self.setGeometry(self.top,self.left,self.width,self.height)
self.creatingTables(test_list)
self.vBoxLayout = QVBoxLayout()
self.vBoxLayout.addWidget(self.tableWidget)
self.setLayout(self.vBoxLayout)
self.textWidgets()
self.vBoxLayout.addWidget(self.timelabel)
self.vBoxLayout.addWidget(self.daylabel)
self.show()
def creatingTables(self, planned_activities):
self.tableWidget = QTableWidget()
self.tableWidget.setRowCount(len(planned_activities))
self.tableWidget.setColumnCount(4)
count = 0
for i in planned_activities:
index = 0 + count
self.label = QLabel(self)
self.label.setPixmap(QPixmap('%s.png' %i.activity))
self.tableWidget.setCellWidget(index,0, self.label)
self.tableWidget.setItem(index,1, QTableWidgetItem(i.activity))
self.tableWidget.setItem(index,2, QTableWidgetItem(i.day))
self.tableWidget.setItem(index,3, QTableWidgetItem(str(i.time)))
count +=1
def textWidgets(self):
self.timelabel = QLabel(self)
self.daylabel = QLabel(self)
self.timelabel.setText("Time:%s" %glo_dict['Time'])
self.daylabel.setText("Day:%s" %glo_dict['Day'])
glo_dict = {'Time': 0000, 'Day': 'None'} #This dict will be updated by other threads in main code
#Simple test object, these objects will be made by the main thread in the other program.
test_list=[]
a = Reminder()
a.time = 1123
a.day = 'Monday'
a.activity = 'rolling'
test_list.append(a)
App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())