Pyqt5 inheritance - python-3.x

full code: link to file
I'm trying to build a GUI using PyQT5, and I have two classes:
In the main class "Window", I have a method to close/exit the GUI, and when I use the method within the class, everything is working
class Window(QMainWindow):
choice = QMessageBox.question(self, ' WARNING!!!!', 'Are you sure to {}'.format(message),
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if choice == QMessageBox.Yes:
print('Quiting Application')
return sys.exit()
else:
pass
But the problem starts here, with the second class, when I try to quit using other class : Q_button.clicked.connect(Window.close_app)
class NewGrid(QWidget):
def __init__(self, parent=None):
super(NewGrid, self).__init__(parent)
grid = QGridLayout()
grid.addWidget(self.createExampleGroup(), 0, 0)
grid.addWidget(self.check_box_vBBU(), 21, 21)
grid.addWidget(self.button_test(), 0, 1)
grid.addWidget(self.quit_button(), 2, 2)
self.setLayout(grid)
def quit_button(self):
groupBox = QGroupBox("Quit_placeholder")
Q_button = QPushButton('Quit', self)
box = QHBoxLayout()
box.addWidget(Q_button)
super()
**Q_button.clicked.connect(Window.close_app)**
groupBox.setLayout(box)
return groupBox
any solution?
edit:
Here is the full code
import sys
from ctypes import windll
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
SCREEN_WIDTH = windll.user32.GetSystemMetrics(0) # 1920
SCREEN_HEIGHT = windll.user32.GetSystemMetrics(1) # 1080
class CustomDialog(QDialog):
def __init__(self, *args, **kwargs):
super(CustomDialog, self).__init__(parent=None)
Qbtn = QDialogButtonBox.Ok | QDialogButtonBox.Cancel
self.buttonBox.accepted(self.accept)
self.buttonBox.rejected(self.reject)
self.layout = QVBoxLayout()
self.layout.addWidget(self.buttonBox)
self.setLayout(self.layout)
class Window(QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.setGeometry(SCREEN_WIDTH / 3, SCREEN_HEIGHT / 3, SCREEN_WIDTH / 3,
SCREEN_HEIGHT / 2) # (start_point_X,start_point_Y,DIMensionX,DimensionY)
self.setWindowIcon(QIcon('dru_icon.png'))
self.setWindowTitle('----------------------DRU GUI-----------------')
self.statusBar()
self.file_menu()
self.view_menu()
self.toolbar_menu()
self.home()
def home(self):
# btn = QPushButton('quit', self)
# btn.clicked.connect(self.close_app)
# make the buttons near the bottom right: 1920-50=450, 1080-50=250
# btn.move(450, 250)
# btn.resize(50, 50)
# btn.move(SCREEN_WIDTH / 3 - 50, SCREEN_HEIGHT / 2 - 50)
label = QLabel("Holla")
label.setAlignment(Qt.AlignBottom)
self.setCentralWidget(label)
widget = NewGrid()
self.setCentralWidget(widget)
self.show()
def toolbar_menu(self):
toolbar = QToolBar("My Main Toolbar")
toolbar.setIconSize(QSize(32, 32)) # manual size
self.addToolBar(toolbar) # showing toolbar
icon1 = self.set_toolbar_icon('new_icon', icon_image='truck--plus')
icon1.triggered.connect(self.close_app)
icon2 = self.set_toolbar_icon('iconNum2')
# icon2.triggered.connect(self.notification_button)
icon3 = self.set_toolbar_icon('iconNum3', icon_image='application-monitor')
def set_toolbar_icon(self, icon_name="NONE", icon_image='animal-monkey.png', Width=32, Length=32):
toolbar = QToolBar("My Main Toolbar")
toolbar.setIconSize(QSize(Width, Length)) # manual size
self.addToolBar(toolbar) # showing toolbar
icon_name = QAction(QIcon(icon_image), icon_name, self)
# icon_name.triggered.connect(
# self.notification_button) # add different command later, for now its quitting,
self.toolBar = self.addToolBar('RUN IT')
# self.toolBar.addAction(icon1) #will be the default icon size from windows
toolbar.addAction(icon_name)
return icon_name
# ------main menu dialog --------
def file_menu(self):
# creating a toolbar with menu
mainMenu = self.menuBar()
fileMenu = mainMenu.addMenu('File')
quit_tooltip = QAction('&Quit', self)
quit_tooltip.setShortcut('Ctrl+Q')
quit_tooltip.setToolTip('close the app')
# quit_tooltip.triggered.connect(self.close_app)
quit_tooltip.triggered.connect(self.close_app)
fileMenu.addAction(quit_tooltip)
def view_menu(self):
mainMenu = self.menuBar()
viewMenu = mainMenu.addMenu('View')
# ------main menu dialog --------
def notification_button(self):
return self.areYouSure_toolbar(message='NO ACTION DEFINED')
def close_app(self): # defined our own method of closing
# choice = QMessageBox.question(self, ' WARNING!!!!', 'Are you sure to quit?',
# QMessageBox.Yes | QMessageBox.No,
# QMessageBox.No) # the last QMessageBox.No is to highliht the option implicitly
choice = self.areYouSure_toolbar(message='Quit')
if choice == QMessageBox.Yes:
print('Quiting Application')
return sys.exit()
else:
pass
def areYouSure_toolbar(self, message='____'):
choice = QMessageBox.question(self, ' WARNING!!!!', 'Are you sure to {}'.format(message),
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No) # the last QMessageBox.No is to highliht the option implicitly
return choice
class NewGrid(QWidget):
def __init__(self, parent=None):
super(NewGrid, self).__init__(parent)
grid = QGridLayout()
grid.addWidget(self.createExampleGroup(), 0, 0)
grid.addWidget(self.check_box_vBBU(), 0, 1)
grid.addWidget(self.button_test(), 1, 0)
grid.addWidget(self.check_box_LPR(), 1, 1)
grid.addWidget(self.quit_button(), 3, 3)
# grid.addWidget(self.createExampleGroup(), 1, 2)
self.setLayout(grid)
# temp = Window()
# self.setWindowTitle("PyQt5 Group Box")
# self.resize(400, 300)
def check_box_vBBU(self):
groupBox = QGroupBox("Input (From vBBU) ")
checkbox1 = QCheckBox('Port {}'.format(1), self)
checkbox2 = QCheckBox('Port {}'.format(2), self)
check_box = QHBoxLayout()
check_box.addWidget(checkbox1)
check_box.addWidget(checkbox2)
check_box.addStretch(1)
groupBox.setLayout(check_box)
return groupBox
def check_box_LPR(self):
groupBox = QGroupBox("Output (from LPR) ")
layout = QHBoxLayout()
for n in range(20):
btn = QCheckBox('LPR' + str(n))
# btn.pressed.connect(self.close_app_Newgrid) #where to connect
layout.addWidget(btn)
# btn.setChecked(True)
num_of_buttons = n
# widget = QWidget()
selectRandom_btn = QPushButton('Random ports')
layout.addWidget(selectRandom_btn)
selectAll_btn = QPushButton('All')
selectAll_btn.pressed.connect(lambda : self.select_buttons(num_of_buttons, btn))
layout.addWidget(selectAll_btn)
groupBox.setLayout(layout)
return groupBox
def select_buttons(self, num_of_buttons,btn):
for x in range(1,num_of_buttons-1):
btn.setC
# btn[1].setChecked(True)
def quit_button(self):
groupBox = QGroupBox("Quit_placeholder")
Q_button = QPushButton('Quit', self)
box = QHBoxLayout()
box.addWidget(Q_button)
super()
# Q_button.clicked.connect(self.close_app_Newgrid)
# Q_button.clicked.connect(Window.close_app)
groupBox.setLayout(box)
return groupBox
def button_test(self):
groupBox = QGroupBox("test buttons")
btn1 = QPushButton("Push me", self)
# btn1.clicked.connect(self.close_app)# need to connect the button somewhere..
vbox = QHBoxLayout()
vbox.addWidget(btn1)
# vbox.addStretch(1)
groupBox.setLayout(vbox)
return groupBox
def createExampleGroup(self):
groupBox = QGroupBox("Data type")
radio1 = QRadioButton("Binary")
radio2 = QRadioButton("Decimal")
radio1.setChecked(True)
vbox = QVBoxLayout()
vbox.addWidget(radio1)
vbox.addWidget(radio2)
vbox.addStretch(1)
groupBox.setLayout(vbox)
return groupBox
def close_app_Newgrid(self): # defined our own method of closing
choice = QMessageBox.question(self, ' WARNING!!!!', 'Are you sure to quit?',
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No) # the last QMessageBox.No is to highliht the option implicitly
if choice == QMessageBox.Yes:
# print('Quiting Application')
return sys.exit()
else:
return
def run():
app = QApplication(sys.argv)
Gui = Window()
sys.exit(app.exec_())
run()
update :
I tried to simplify the solution below:
for w in QApplication.topLevelWidgets():
if isinstance(w,Window):
w = True
windows = w

The connection is between the signal of one object and the slot of another, not between classes, so the instruction is incorrect.
So in order to perform this task we must get some way to the Window object, a possible solution is to take advantage of Window is the window, so it is a top-Level for it we use the topLevelWidgets() method and we filter through isinstance():
def quit_button(self):
groupBox = QGroupBox("Quit_placeholder")
Q_button = QPushButton('Quit', self)
box = QHBoxLayout()
box.addWidget(Q_button)
#Q_button.clicked.connect(self.close_app_Newgrid)
windows = [w for w in QApplication.topLevelWidgets() if isinstance(w, Window)]
if windows:
Q_button.clicked.connect(windows[0].close_app)
groupBox.setLayout(box)
return groupBox
Note: the problem is not due to inheritance.

Related

How can i draw interactively a line in QGraphicScene in PyQt5

I'm trying to draw a line interactively but I can't figure out how to do it. Anyone can help me?
I'm using PyQt5. I create a QGraphicsScene, I override mouse press event but when I try to draw the draw the it draw nothing.
Finally, I have another question. How can I snap this line to the grid?
import math
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class neGraphicScene(QGraphicsScene):
_colorBackGround: str
_colorLightLines: str
_colorDarkLines: str
_penLight: QPen
_penDark: QPen
gridSize: int = 20
gridSquares: int = 5
isLineDrawing = False
def __init__(self, parent=None):
QGraphicsScene.__init__(self, QRectF(-1000, -1000, 2000, 2000), parent)
self.setSceneColor()
self.begin, self.destination = QPoint(), QPoint()
def setSceneColor(self, _lightLines="#2f2f2f", _darkLines="#292929", _background="#393939"):
self._colorBackGround = _background
self._colorLightLines = _lightLines
self._colorDarkLines = _darkLines
self._penLight = QPen(QColor(self._colorLightLines))
self._penLight.setWidth(1)
self._penDark = QPen(QColor(self._colorDarkLines))
self._penDark.setWidth(2)
self.setBackgroundBrush(QColor(self._colorBackGround))
def setGraphicScene(self, width, height):
self.setSceneRect(-width // 2, -height // 2, width, height)
def mouseDoubleClickEvent(self, event):
QGraphicsScene.mouseMoveEvent(self, event)
def mousePressEvent(self, event):
self.isLineDrawing = True
if event.buttons() & Qt.LeftButton:
print('Point 1')
self.begin = event.pos()
self.destination = self.begin
self.update()
def mouseMoveEvent(self, event):
if event.buttons() & Qt.LeftButton:
print('Point 2')
self.destination = event.pos()
self.update()
def mouseReleaseEvent(self, event):
self.isLineDrawing = False
print('Point 3')
def drawBackground(self, painter, rect):
super(neGraphicScene, self).drawBackground(painter, rect)
# self.drawBackgroundGrid(painter, rect)
if self.isLineDrawing:
if not self.begin.isNull() and not self.destination.isNull():
line = QLineF(self.begin, self.destination)
painter.setPen(Qt.red)
painter.drawLine(line)
This is the QGraphicsView and the QWidgetStuff to made the minimal example working properly:
class neGraphicView(QGraphicsView):
def __init__(self, graphicScene, parent=None):
super().__init__(parent)
# self._dragPos = QPoint(0, 0)
self.sharedGraphicScene = graphicScene
self.setScene(self.sharedGraphicScene)
self._mousePressed = False
self._isPanning = False
self.initUI()
def initUI(self):
self.setRenderHints(
QPainter.Antialiasing | QPainter.HighQualityAntialiasing |
QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setDragMode(QGraphicsView.RubberBandDrag)
class NodeEditorWindow(QWidget):
mainLayout: QVBoxLayout
mainGraphicsScene: neGraphicScene
view: neGraphicView
def __init__(self, parent=None):
super(NodeEditorWindow, self).__init__(parent)
self.initUI()
def initUI(self):
self.setGeometry(200, 200, 800, 600)
self.mainLayout = QVBoxLayout()
self.mainLayout.setContentsMargins(0, 0, 0, 0)
self.setLayout(self.mainLayout)
self.mainGraphicsScene = neGraphicScene()
self.view = neGraphicView(self.mainGraphicsScene, self)
self.mainLayout.addWidget(self.view)
self.setWindowTitle("Node Editor")
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyle("Fusion")
win = NodeEditorWindow()
win.show()
sys.exit(app.exec())
This is the grid function:
def drawBackgroundGrid(self, _painter, _rect):
# here we create our grid
_left = int(math.floor(_rect.left()))
_right = int(math.ceil(_rect.right()))
_top = int(math.floor(_rect.top()))
_bottom = int(math.ceil(_rect.bottom()))
first_left = _left - (_left % self.gridSize)
first_top = _top - (_top % self.gridSize)
try:
# compute all lines to be drawn
lightLines, darkLines = [], []
for x in range(first_left, _right, self.gridSize):
if x % (self.gridSize * self.gridSquares) != 0:
lightLines.append(QLineF(x, _top, x, _bottom))
else:
darkLines.append(QLineF(x, _top, x, _bottom))
for y in range(first_top, _bottom, self.gridSize):
if y % (self.gridSize * self.gridSquares) != 0:
lightLines.append(QLineF(_left, y, _right, y))
else:
darkLines.append(QLineF(_left, y, _right, y))
# draw the lines
_painter.setPen(self._penLight)
_painter.drawLines(*lightLines)
_painter.setPen(self._penDark)
_painter.drawLines(*darkLines)
except Exception as e:
# print(e)
pass

PyQt unable to add tableWIdget to existing application

I have an existing application to which I would like to add a table widget. Currently it looks like this:
I am trying to add a PyQt5 table following this tutorial.
My code is as follows:
class App(QMainWindow):
def __init__(self):
super().__init__()
self.player = QMediaPlayer() # QMediaPlayer class allows the playing of a media source.
self.playlist = QMediaPlaylist() # QMediaPlaylist class provides a list of media content to play.
self.title = 'PyTunes'
self.left = 300
self.top = 300
self.width = 300
self.height = 150
self.color = 0 # 0- toggle to dark 1- toggle to light
self.userAction = -1 # 0- stopped, 1- playing 2-paused
self.setup_UI()
def setup_UI(self):
# Add file menu
menubar = self.menuBar()
filemenu = menubar.addMenu('File')
windowmenu = menubar.addMenu('Window')
help_act = QAction('Open Help', self)
folder_act = QAction('Open Folder', self)
theme_act = QAction('Toggle light/dark theme', self)
folder_act.setShortcut('Ctrl+D')
help_act.setShortcut('Ctrl+H')
theme_act.setShortcut('Ctrl+T')
filemenu.addAction(folder_act)
filemenu.addAction(help_act)
windowmenu.addAction(theme_act)
help_act.triggered.connect(self.open_help)
folder_act.triggered.connect(self.add_files)
theme_act.triggered.connect(self.toggle_colors)
self.add_controls()
self.createTable()
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.toggle_colors()
self.show()
def add_controls(self):
wid = QWidget(self)
self.setCentralWidget(wid)
# Add song controls
volumeslider = QSlider(Qt.Horizontal, self)
volumeslider.setFocusPolicy(Qt.NoFocus)
volumeslider.valueChanged[int].connect(self.change_volume)
volumeslider.setValue(100)
play_btn = QPushButton('Play') # play button
pause_btn = QPushButton('Pause') # pause button
stop_btn = QPushButton('Stop') # stop button
# Add playlist controls
prev_btn = QPushButton('Prev')
shuffle_btn = QPushButton('Shuffle')
next_btn = QPushButton('Next')
sort_btn = QPushButton('Sort')
search_btn = QPushButton('Search')
remove_btn = QPushButton('Remove')
# Add button layouts
control_area = QVBoxLayout() # centralWidget
controls = QHBoxLayout()
playlist_ctrl_layout = QHBoxLayout()
playlist_func = QHBoxLayout()
# Add buttons to song controls layout
controls.addWidget(play_btn)
controls.addWidget(pause_btn)
controls.addWidget(stop_btn)
# Add buttons to playlist controls layout
playlist_ctrl_layout.addWidget(prev_btn)
playlist_ctrl_layout.addWidget(shuffle_btn)
playlist_ctrl_layout.addWidget(next_btn)
playlist_func.addWidget(sort_btn)
playlist_func.addWidget(search_btn)
playlist_func.addWidget(remove_btn)
# Add to vertical layout
control_area.addLayout(controls)
control_area.addLayout(playlist_ctrl_layout)
control_area.addWidget(volumeslider)
control_area.addLayout(playlist_func)
# control_area.addWidget(QTableWidget)
# control_area.addWidget(self.tableWidget)
wid.setLayout(control_area)
# Connect each signal to their appropriate function
play_btn.clicked.connect(self.play_handler)
pause_btn.clicked.connect(self.pause_handler)
stop_btn.clicked.connect(self.stop_handler)
prev_btn.clicked.connect(self.prev_song)
shuffle_btn.clicked.connect(self.shuffle_list)
next_btn.clicked.connect(self.next_song)
sort_btn.clicked.connect(self.sort_handler)
search_btn.clicked.connect(self.search_handler)
remove_btn.clicked.connect(self.remove_handler)
self.statusBar()
# Signal emitted when current media changes. Call song_changed
self.playlist.currentMediaChanged.connect(self.song_changed)
def createTable(self):
# Create table
self.tableWidget = QTableWidget()
self.tableWidget.setRowCount(4)
self.tableWidget.setColumnCount(2)
self.tableWidget.setItem(0, 0, QTableWidgetItem("Cell (1,1)"))
self.tableWidget.setItem(0, 1, QTableWidgetItem("Cell (1,2)"))
self.tableWidget.setItem(1, 0, QTableWidgetItem("Cell (2,1)"))
self.tableWidget.setItem(1, 1, QTableWidgetItem("Cell (2,2)"))
self.tableWidget.setItem(2, 0, QTableWidgetItem("Cell (3,1)"))
self.tableWidget.setItem(2, 1, QTableWidgetItem("Cell (3,2)"))
self.tableWidget.setItem(3, 0, QTableWidgetItem("Cell (4,1)"))
self.tableWidget.setItem(3, 1, QTableWidgetItem("Cell (4,2)"))
self.tableWidget.move(0, 0)
# table selection change
self.tableWidget.doubleClicked.connect(self.on_click)
#pyqtSlot()
def on_click(self):
print("\n")
for currentQTableWidgetItem in self.tableWidget.selectedItems():
print(currentQTableWidgetItem.row(), currentQTableWidgetItem.column(), currentQTableWidgetItem.text())
I added the box layout in add_controls() and now I am trying to add the table to the box layout.
I have tried: control_area.addWidget(QTableWidget) but this returns the error:
control_area.addWidget(QTableWidget)
TypeError: addWidget(self, QWidget, stretch: int = 0, alignment: Union[Qt.Alignment, Qt.AlignmentFlag] = Qt.Alignment()): argument 1 has unexpected type 'sip.wrappertype'
I have also tried: control_area.addWidget(self.tableWidget) but this returns the error:
control_area.addWidget(self.tableWidget)
AttributeError: 'App' object has no attribute 'tableWidget'
Any suggestions on what I am doing wrong and how this can be rectified? Thanks in advance
Try it:
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtMultimedia import QMediaPlayer, QMediaPlaylist
class App(QMainWindow):
def __init__(self):
super().__init__()
self.player = QMediaPlayer() # QMediaPlayer class allows the playing of a media source.
self.playlist = QMediaPlaylist() # QMediaPlaylist class provides a list of media content to play.
self.title = 'PyTunes'
self.left = 300
self.top = 300
self.width = 300
self.height = 150
self.color = 0 # 0- toggle to dark 1- toggle to light
self.userAction = -1 # 0- stopped, 1- playing 2-paused
self.setup_UI()
def setup_UI(self):
# Add file menu
menubar = self.menuBar()
filemenu = menubar.addMenu('File')
windowmenu = menubar.addMenu('Window')
help_act = QAction('Open Help', self)
folder_act = QAction('Open Folder', self)
theme_act = QAction('Toggle light/dark theme', self)
folder_act.setShortcut('Ctrl+D')
help_act.setShortcut( 'Ctrl+H')
theme_act.setShortcut( 'Ctrl+T')
filemenu.addAction(folder_act)
filemenu.addAction(help_act)
windowmenu.addAction(theme_act)
# help_act.triggered.connect( self.open_help)
# folder_act.triggered.connect(self.add_files)
# theme_act.triggered.connect( self.toggle_colors)
self.add_controls()
self.createTable()
self.control_area.addWidget(self.tableWidget) # <===============
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
#? self.toggle_colors()
self.show()
def add_controls(self):
wid = QWidget(self)
self.setCentralWidget(wid)
# Add song controls
volumeslider = QSlider(Qt.Horizontal, self)
volumeslider.setFocusPolicy(Qt.NoFocus)
# volumeslider.valueChanged[int].connect(self.change_volume)
volumeslider.setValue(100)
play_btn = QPushButton('Play') # play button
pause_btn = QPushButton('Pause') # pause button
stop_btn = QPushButton('Stop') # stop button
# Add playlist controls
prev_btn = QPushButton('Prev')
shuffle_btn = QPushButton('Shuffle')
next_btn = QPushButton('Next')
sort_btn = QPushButton('Sort')
search_btn = QPushButton('Search')
remove_btn = QPushButton('Remove')
# Add button layouts
self.control_area = QVBoxLayout() # + self.
controls = QHBoxLayout()
playlist_ctrl_layout = QHBoxLayout()
playlist_func = QHBoxLayout()
# Add buttons to song controls layout
controls.addWidget(play_btn)
controls.addWidget(pause_btn)
controls.addWidget(stop_btn)
# Add buttons to playlist controls layout
playlist_ctrl_layout.addWidget(prev_btn)
playlist_ctrl_layout.addWidget(shuffle_btn)
playlist_ctrl_layout.addWidget(next_btn)
playlist_func.addWidget(sort_btn)
playlist_func.addWidget(search_btn)
playlist_func.addWidget(remove_btn)
# Add to vertical layout
self.control_area.addLayout(controls) # + self.
self.control_area.addLayout(playlist_ctrl_layout) # + self.
self.control_area.addWidget(volumeslider) # + self.
self.control_area.addLayout(playlist_func) # + self.
# control_area.addWidget(QTableWidget)
# control_area.addWidget(self.tableWidget)
wid.setLayout(self.control_area) # + self.
# Connect each signal to their appropriate function
# play_btn.clicked.connect(self.play_handler)
# pause_btn.clicked.connect(self.pause_handler)
# stop_btn.clicked.connect(self.stop_handler)
# prev_btn.clicked.connect(self.prev_song)
# shuffle_btn.clicked.connect(self.shuffle_list)
# next_btn.clicked.connect(self.next_song)
# sort_btn.clicked.connect(self.sort_handler)
# search_btn.clicked.connect(self.search_handler)
# remove_btn.clicked.connect(self.remove_handler)
self.statusBar()
# Signal emitted when current media changes. Call song_changed
# self.playlist.currentMediaChanged.connect(self.song_changed)
def createTable(self):
# Create table
self.tableWidget = QTableWidget()
self.tableWidget.setRowCount(4)
self.tableWidget.setColumnCount(2)
self.tableWidget.setItem(0, 0, QTableWidgetItem("Cell (1,1)"))
self.tableWidget.setItem(0, 1, QTableWidgetItem("Cell (1,2)"))
self.tableWidget.setItem(1, 0, QTableWidgetItem("Cell (2,1)"))
self.tableWidget.setItem(1, 1, QTableWidgetItem("Cell (2,2)"))
self.tableWidget.setItem(2, 0, QTableWidgetItem("Cell (3,1)"))
self.tableWidget.setItem(2, 1, QTableWidgetItem("Cell (3,2)"))
self.tableWidget.setItem(3, 0, QTableWidgetItem("Cell (4,1)"))
self.tableWidget.setItem(3, 1, QTableWidgetItem("Cell (4,2)"))
self.tableWidget.move(0, 0)
# table selection change
self.tableWidget.doubleClicked.connect(self.on_click)
#pyqtSlot()
def on_click(self):
print("\n")
for currentQTableWidgetItem in self.tableWidget.selectedItems():
print(currentQTableWidgetItem.row(),
currentQTableWidgetItem.column(),
currentQTableWidgetItem.text())
if __name__ == '__main__':
app = QApplication(sys.argv)
main = App()
main.show()
sys.exit(app.exec_())
Solved, issue was here:
self.add_controls()
self.createTable()
since I was calling add_controls() before creating the table, resulting in:
'App' object has no attribute 'tableWidget'

How to align a label with my selection list

I am using PyQt5 to create a GUI program.
I have a problem when creating a label beside the QComboBox.
If I didnt create a label beside the QComboBox , it would look like the picture down below.
But if I added the label it would be like this :
The selection list just moved down a little bit automatically.
How can I do to make it be align to the label at the left-hand side?
(I mean just beside the CASE TYPE)
(I comment the critical part in my code)
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5 import QtWidgets
import xml.etree.cElementTree as ET
class App(QMainWindow):
def __init__(self,parent=None):
super().__init__()
self.title = "Automation"
self.left = 10
self.top = 10
self.width = 400
self.height = 200
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
# Create textbox
self.textbox = QLineEdit(self)
self.textbox.move(80, 20)
#self.textbox.resize(50,40)
self.textbox2 = QLineEdit(self)
self.textbox2.move(80, 80)
#self.textbox2.resize(50,40)
# Create text beside editor
wid1 = QWidget(self)
self.setCentralWidget(wid1)
mytext = QFormLayout()
mytext.addRow("CASE INDEX",self.textbox)
mytext.addRow("CASE TYPE",self.textbox2)
wid1.setLayout(mytext)
#################### Critical Part #######################
self.CB = QComboBox()
self.CB.addItems(["RvR","Turntable","Fixrate"])
self.CB.currentIndexChanged.connect(self.selectionchange)
label = QLabel("CASE TYPE")
mytext.addRow(label,self.CB) # this one makes the list shift down a little bit
mytext.addWidget(self.CB)
wid1.setLayout(mytext)
##########################################################
# Create a button in the window
self.button = QPushButton('Show text', self)
self.button.move(20,150)
# connect button to function on_click
self.button.clicked.connect(self.on_click)
self.center()
self.show()
#pyqtSlot()
def on_click(self):
textboxValue = self.textbox.text()
textboxValue2 = self.textbox2.text()
QMessageBox.question(self, 'Message - pythonspot.com', "You typed: "+ textboxValue + " , second msg is: " + textboxValue2, QMessageBox.Ok, QMessageBox.Ok)
print(textboxValue)
self.textbox.setText("")
self.textbox2.setText("")
def center(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
def selectionchange(self,i):
print ("Items in the list are :")
for count in range(self.CB.count()):
print (self.CB.itemText(count))
print ("Current index",i,"selection changed ",self.CB.currentText())
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
Please , I need your help.
Thanks.
Try it:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5 import QtWidgets
import xml.etree.cElementTree as ET
class App(QMainWindow):
def __init__(self,parent=None):
super().__init__()
self.title = "Automation"
self.left = 10
self.top = 10
self.width = 400
self.height = 200
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
# Create textbox
self.textbox = QLineEdit(self)
# self.textbox.move(80, 20)
#self.textbox.resize(50,40)
self.textbox2 = QLineEdit(self)
# self.textbox2.move(80, 80)
#self.textbox2.resize(50,40)
# Create text beside editor
wid1 = QWidget(self)
self.setCentralWidget(wid1)
mytext = QFormLayout()
mytext.addRow("CASE INDEX", self.textbox)
mytext.addRow("CASE TYPE", self.textbox2)
# wid1.setLayout(mytext)
#################### Critical Part #######################
self.CB = QComboBox()
self.CB.addItems(["RvR","Turntable","Fixrate"])
self.CB.currentIndexChanged.connect(self.selectionchange)
label = QLabel("CASE TYPE")
mytext.addRow(label, self.CB) # this one makes the list shift down a little bit
# mytext.addWidget(self.CB)
# wid1.setLayout(mytext)
##########################################################
# Create a button in the window
self.button = QPushButton('Show text', self)
# self.button.move(20,150)
# connect button to function on_click
self.button.clicked.connect(self.on_click)
layoutV = QVBoxLayout(wid1) # + wid1 <<<========
layoutV.addLayout(mytext) # +
layoutV.addWidget(self.button, alignment=Qt.AlignLeft) # +
self.center()
self.show()
#pyqtSlot()
def on_click(self):
textboxValue = self.textbox.text()
textboxValue2 = self.textbox2.text()
QMessageBox.question(self, 'Message - pythonspot.com', "You typed: "+ textboxValue + " , second msg is: " + textboxValue2, QMessageBox.Ok, QMessageBox.Ok)
print(textboxValue)
self.textbox.setText("")
self.textbox2.setText("")
def center(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
def selectionchange(self,i):
print ("Items in the list are :")
for count in range(self.CB.count()):
print (self.CB.itemText(count))
print ("Current index",i,"selection changed ",self.CB.currentText())
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())

How to add TextEdit, Labels and Buttons that move when Window Size is moved using PyQt?

I am new to PyQt, but for the past days I was trying to create a GUI which has labels, TextEdit and buttons which move when the Window size is moved (minimized or enlarged), I tried doing it so but the Buttons get stuck in the top left corner while the labels and TextEdit completely don't show up on the form, Please do help . Here is a snippet of my codes
import sys
from PyQt4 import QtGui, QtCore
class Window(QtGui.QMainWindow, QtGui.QWidget):
` def __init__(self):
super(Window, self).__init__()
self.setGeometry(50, 50, 500, 300)
self.setWindowTitle("PTE")
self.setWindowIcon(QtGui.QIcon('.png'))
self.center()
# Adding Menu to the GUI
quitAction = QtGui.QAction(QtGui.QIcon('exit.png'), "&Quit", self)
quitAction.setShortcut("Ctrl+Q")
quitAction.setStatusTip('Exit Application')
quitAction.triggered.connect(self.close_application)
undoAction = QtGui.QAction(QtGui.QIcon('undo.png'), "&Undo", self)
undoAction.setShortcut("Ctrl+Z")
undoAction.triggered.connect(self.close_application)
aboutAction = QtGui.QAction("&About PTE...", self)
self.statusBar()
#Actual Main Menu with options
mainMenu = self.menuBar()
fileMenu = mainMenu.addMenu('&File')
fileMenu.addAction(quitAction)
fileMenu = mainMenu.addMenu('&Edit')
fileMenu.addAction(undoAction)
fileMenu = mainMenu.addMenu('&Help')
fileMenu.addAction(aboutAction)
self.home()
#Centering Window on the screen
def center(self):
gui = self.frameGeometry()
cp = QtGui.QDesktopWidget().availableGeometry().center()
gui.moveCenter(cp)
self.move(gui.topLeft())
def home(self):
#Buttons
qbtn = QtGui.QPushButton('Quit', self)
qbtn.clicked.connect(self.close_application)
rbtn = QtGui.QPushButton("Run", self)
rbtn.clicked.connect(self.close_application)
hbox = QtGui.QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(qbtn)
hbox.addWidget(rbtn)
vbox = QtGui.QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)
self.setLayout(vbox)
self.show()
#Labels and TextBox
Intervals = QtGui.QLabel('Number of intervals (0<=20) :')
Timesteps = QtGui.QLabel('Number of time steps (<=1000) : ')
IntervalsEdit = QtGui.QLineEdit()
TimestepsEdit = QtGui.QLineEdit()
grid = QtGui.QGridLayout()
grid.setSpacing(2)
grid.addWidget(Intervals, 1, 0)
grid.addWidget(IntervalsEdit, 1, 1)
grid.addWidget(Timesteps, 2, 0)
grid.addWidget(TimestepsEdit, 2, 1)
self.setLayout(grid)
self.show()
#What to display when the app is closed
def close_application(self):
#Popup message before closing the application in Binary
choice = QtGui.QMessageBox.question(self, 'Message',"Are you sure you want to exit?",
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No )
if choice == QtGui.QMessageBox.Yes:
print(" Until Next Time")
sys.exit()
else:
pass
def run():
app = QtGui.QApplication(sys.argv)
GUI = Window()
sys.exit(app.exec_())
run()
Hey i fixed the issues with your code. In my fix, i added the QGridLayout to the QHBoxLayout. If you want the grid in another place you might need to nest both layouts in a 3rd layout.
Note that you are using setLayout for grid and for vbox when you can only set 1 layout. You also call show() twice, which you don't need. You also add a QVBoxLayout to hbox but do not add any widget. As it is, this is useless. If you want hbox and grid to be vertically aligned you will need to vbox.addLayout(grid) and self.setLayout(vbox) instead.
import sys
from PyQt4 import QtGui, QtCore
class Window(QtGui.QMainWindow, QtGui.QWidget):
` def __init__(self):
super(Window, self).__init__()
self.setGeometry(50, 50, 500, 300)
self.setWindowTitle("PTE")
self.setWindowIcon(QtGui.QIcon('.png'))
self.center()
# Adding Menu to the GUI
quitAction = QtGui.QAction(QtGui.QIcon('exit.png'), "&Quit", self)
quitAction.setShortcut("Ctrl+Q")
quitAction.setStatusTip('Exit Application')
quitAction.triggered.connect(self.close_application)
undoAction = QtGui.QAction(QtGui.QIcon('undo.png'), "&Undo", self)
undoAction.setShortcut("Ctrl+Z")
undoAction.triggered.connect(self.close_application)
aboutAction = QtGui.QAction("&About PTE...", self)
self.statusBar()
#Actual Main Menu with options
mainMenu = self.menuBar()
fileMenu = mainMenu.addMenu('&File')
fileMenu.addAction(quitAction)
fileMenu = mainMenu.addMenu('&Edit')
fileMenu.addAction(undoAction)
fileMenu = mainMenu.addMenu('&Help')
fileMenu.addAction(aboutAction)
self.home()
#Centering Window on the screen
def center(self):
gui = self.frameGeometry()
cp = QtGui.QDesktopWidget().availableGeometry().center()
gui.moveCenter(cp)
self.move(gui.topLeft())
def home(self):
#Buttons
qbtn = QtGui.QPushButton('Quit', self)
qbtn.clicked.connect(self.close_application)
rbtn = QtGui.QPushButton("Run", self)
rbtn.clicked.connect(self.close_application)
hbox = QtGui.QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(qbtn)
hbox.addWidget(rbtn)
vbox = QtGui.QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)
#self.show() #this only needs to be called once
#Labels and TextBox
Intervals = QtGui.QLabel('Number of intervals (0<=20) :')
Timesteps = QtGui.QLabel('Number of time steps (<=1000) : ')
IntervalsEdit = QtGui.QLineEdit()
TimestepsEdit = QtGui.QLineEdit()
grid = QtGui.QGridLayout()
grid.setSpacing(2)
grid.addWidget(Intervals, 1, 0)
grid.addWidget(IntervalsEdit, 1, 1)
grid.addWidget(Timesteps, 2, 0)
grid.addWidget(TimestepsEdit, 2, 1)
hbox.addLayout(grid) #this will add the grid to the horizontal layout.
#if you want it to be vertcally aligned change this to vbox.addLayout(grid)...
#... and this to self.setLayout(vbox)
self.setLayout(hbox)
self.show()
#What to display when the app is closed
def close_application(self):
#Popup message before closing the application in Binary
choice = QtGui.QMessageBox.question(self, 'Message',"Are you sure you want to exit?",
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No )
if choice == QtGui.QMessageBox.Yes:
print(" Until Next Time")
sys.exit()
else:
pass

pyqt scrollarea not resized after dragndrop

short version:
- take the code, run it, (all you need is two png icons)
- resize the window to be a lot larger
- dragndrop one of the icon far away (at least 300+ pixels away)
- then resize window back to original size
- then try to scroll to see the icon you dragndropped away.
- you will not be able. because scrollarea is too small.
- why?
long version:
i'm having trouble figuring how to update my scrollarea to reflect added or modified contents in my application.
i'm displaying icons, i can dragndrop them.
if i make the window bigger, dragndrop one icon to the bottom,
and then size back my window,
the scrollarea does not allow me to scroll to the bottom to see my icon.
basicaly, once the app started, scrollarea dimension never change.
how can i make the scrollarea, upon dragndrop, to update to new size ?
it could be bigger like shown in the screenshot below,
or smaller if all my icons are grouped in upper left corner for example..
if the content fit in the window, i will not show the slider.
here's a screenshot showing the problem,
it's the same window, i just resize it, and dragndrop one icon at the bottom:
(scrollarea is not updated, so i cannot scroll down to my icon i've put at the bottom)
here's the code so far:
#!/usr/bin/python3
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class DragWidget(QFrame):
def __init__(self, parent=None):
super(DragWidget, self).__init__(parent)
self.setMinimumSize(200, 200)
self.setAcceptDrops(True)
test_icon1 = QLabel(self)
test_icon1.setPixmap(QPixmap('./images/closeicon.png'))
test_icon1.move(20, 20)
test_icon1.show()
test_icon1.setAttribute(Qt.WA_DeleteOnClose)
test_icon2 = QLabel(self)
test_icon2.setPixmap(QPixmap('./images/openicon.png'))
test_icon2.move(60, 20)
test_icon2.show()
test_icon2.setAttribute(Qt.WA_DeleteOnClose)
def dragEnterEvent(self, event):
if event.mimeData().hasFormat('application/x-dnditemdata'):
if event.source() == self:
event.setDropAction(Qt.MoveAction)
event.accept()
else:
event.acceptProposedAction()
else:
event.ignore()
dragMoveEvent = dragEnterEvent
def dropEvent(self, event):
if event.mimeData().hasFormat('application/x-dnditemdata'):
itemData = event.mimeData().data('application/x-dnditemdata')
dataStream = QDataStream(itemData, QIODevice.ReadOnly)
pixmap = QPixmap()
offset = QPoint()
dataStream >> pixmap >> offset
newIcon = QLabel(self)
newIcon.setPixmap(pixmap)
newIcon.move(event.pos() - offset)
newIcon.show()
newIcon.setAttribute(Qt.WA_DeleteOnClose)
if event.source() == self:
event.setDropAction(Qt.MoveAction)
event.accept()
else:
event.acceptProposedAction()
else:
event.ignore()
def mousePressEvent(self, event):
child = self.childAt(event.pos())
if not child:
return
pixmap = QPixmap(child.pixmap())
itemData = QByteArray()
dataStream = QDataStream(itemData, QIODevice.WriteOnly)
dataStream << pixmap << QPoint(event.pos() - child.pos())
mimeData = QMimeData()
mimeData.setData('application/x-dnditemdata', itemData)
drag = QDrag(self)
drag.setMimeData(mimeData)
drag.setPixmap(pixmap)
drag.setHotSpot(event.pos() - child.pos())
tempPixmap = QPixmap(pixmap)
painter = QPainter()
painter.begin(tempPixmap)
painter.fillRect(pixmap.rect(), QColor(127, 127, 127, 127))
painter.end()
child.setPixmap(tempPixmap)
if drag.exec_(Qt.CopyAction | Qt.MoveAction) == Qt.MoveAction:
child.close()
else:
child.show()
child.setPixmap(pixmap)
class Window(QWidget):
def __init__(self, parent=None):
super(Window, self).__init__()
widget = QWidget()
palette = QPalette()
palette.setBrush(QPalette.Background, QBrush(QPixmap("images/pattern.png")))
widget.setPalette(palette)
layout = QVBoxLayout(self)
layout.addWidget(DragWidget())
widget.setLayout(layout)
scroll = QScrollArea()
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
scroll.setWidgetResizable(True)
scroll.setWidget(widget)
vlayout = QVBoxLayout(self)
vlayout.setContentsMargins(0, 0, 0, 0)
vlayout.setSpacing(0)
vlayout.addWidget(scroll)
self.setLayout(vlayout)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window('./')
sys.exit(app.exec_())
it turned out, i needed to modify dropEvent method,
to take the X and Y of the dropped icon and use those values for setMinimumSize().
like this:
#!/usr/bin/python3
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class DragWidget(QFrame):
def __init__(self, parent=None):
super(DragWidget, self).__init__(parent)
self.setMinimumSize(200, 200)
self.setAcceptDrops(True)
self.test_icon1 = QLabel(self)
self.test_icon1.setPixmap(QPixmap('./images/closeicon.png'))
self.test_icon1.move(20, 20)
self.test_icon1.show()
self.test_icon1.setAttribute(Qt.WA_DeleteOnClose)
self.test_icon2 = QLabel(self)
self.test_icon2.setPixmap(QPixmap('./images/openicon.png'))
self.test_icon2.move(60, 20)
self.test_icon2.show()
self.test_icon2.setAttribute(Qt.WA_DeleteOnClose)
def dragEnterEvent(self, event):
if event.mimeData().hasFormat('application/x-dnditemdata'):
if event.source() == self:
event.setDropAction(Qt.MoveAction)
event.accept()
else:
event.acceptProposedAction()
else:
event.ignore()
dragMoveEvent = dragEnterEvent
def dropEvent(self, event):
if event.mimeData().hasFormat('application/x-dnditemdata'):
itemData = event.mimeData().data('application/x-dnditemdata')
dataStream = QDataStream(itemData, QIODevice.ReadOnly)
pixmap = QPixmap()
offset = QPoint()
dataStream >> pixmap >> offset
newIcon = QLabel(self)
newIcon.setPixmap(pixmap)
newIcon.move(event.pos() - offset)
newIcon.show()
newIcon.setAttribute(Qt.WA_DeleteOnClose)
if newIcon.y()+32 > self.minimumHeight():
self.setMinimumHeight(newIcon.y()+32)
if newIcon.x()+32 > self.minimumWidth():
self.setMinimumWidth(newIcon.x()+32)
if event.source() == self:
event.setDropAction(Qt.MoveAction)
event.accept()
else:
event.acceptProposedAction()
else:
event.ignore()
def mousePressEvent(self, event):
child = self.childAt(event.pos())
if not child:
return
pixmap = QPixmap(child.pixmap())
itemData = QByteArray()
dataStream = QDataStream(itemData, QIODevice.WriteOnly)
dataStream << pixmap << QPoint(event.pos() - child.pos())
mimeData = QMimeData()
mimeData.setData('application/x-dnditemdata', itemData)
drag = QDrag(self)
drag.setMimeData(mimeData)
drag.setPixmap(pixmap)
drag.setHotSpot(event.pos() - child.pos())
tempPixmap = QPixmap(pixmap)
painter = QPainter()
painter.begin(tempPixmap)
painter.fillRect(pixmap.rect(), QColor(127, 127, 127, 127))
painter.end()
child.setPixmap(tempPixmap)
if drag.exec_(Qt.CopyAction | Qt.MoveAction) == Qt.MoveAction:
child.close()
else:
child.show()
child.setPixmap(pixmap)
class Window(QWidget):
def __init__(self, parent=None):
super(Window, self).__init__()
self.pattern = "images/pattern.png"
self.widget = QWidget()
self.palette = QPalette()
self.palette.setBrush(QPalette.Background, QBrush(QPixmap(self.pattern)))
self.widget.setPalette(self.palette)
layout = QVBoxLayout(self)
layout.addWidget(DragWidget())
self.widget.setLayout(layout)
scroll = QScrollArea()
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
scroll.setWidgetResizable(True)
scroll.setWidget(self.widget)
vlayout = QVBoxLayout(self)
vlayout.setContentsMargins(0, 0, 0, 0)
vlayout.setSpacing(0)
vlayout.addWidget(scroll)
self.setLayout(vlayout)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window('./')
window2 = Window('./')
sys.exit(app.exec_())
note the dropEvent() method of DragWidget() class.
if newIcon.y()+32 > self.minimumHeight():
self.setMinimumHeight(newIcon.y()+32)
if newIcon.x()+32 > self.minimumWidth():
self.setMinimumWidth(newIcon.x()+32)
so if the icon new position is greater than
the minimumSize (minimumWidth and minimumHeight),
then add the offset to self.minimumSize
thanks to Avaris from #pyqt channel for the help :)

Resources