Combine PyQt4 CheckBox Functions into single function - python

I've been working on an XCOPY GUI and I added in check boxes to select the desired xcopy switches. I have it all working, but I'm trying to condense the code as I'm sure there is a way to do it, I'm just not sure how. Basically, for each switch (E, C, H, Y, I) I do a function call to check the state of the CheckBox and return the value for my x_copy function's subprocess call.
How could I go about making a call to a single function and have it check the states of all my checkbox widgets?
import sys
from PyQt4 import QtGui
import os
import subprocess
class XcopyMain(QtGui.QWidget):
def __init__(self):
super(XcopyMain, self).__init__()
# Declare Widgets
src_btn = QtGui.QPushButton('Source')
dst_btn = QtGui.QPushButton('Destination')
prev_btn = QtGui.QPushButton('Preview File(s)')
x_copy_btn = QtGui.QPushButton('Start XCOPY')
switch_lbl = QtGui.QLabel('Switches:')
# self.progress = QtGui.QProgressBar(self)
self.src_line = QtGui.QLineEdit()
self.dst_line = QtGui.QLineEdit()
self.selected_files = QtGui.QTextEdit()
self.e_chk = QtGui.QCheckBox('E')
self.e_chk.stateChanged.connect(self.e_apply)
self.c_chk = QtGui.QCheckBox('C')
self.c_chk.stateChanged.connect(self.c_apply)
self.h_chk = QtGui.QCheckBox('H')
self.h_chk.stateChanged.connect(self.h_apply)
self.y_chk = QtGui.QCheckBox('Y')
self.y_chk.stateChanged.connect(self.y_apply)
self.i_chk = QtGui.QCheckBox('I')
self.i_chk.stateChanged.connect(self.i_apply)
# Declare Emit / Slot
src_btn.clicked.connect(self.src_select)
dst_btn.clicked.connect(self.dst_select)
prev_btn.clicked.connect(self.list_files)
x_copy_btn.clicked.connect(self.x_copy)
# Declare Layout
mainLayout = QtGui.QGridLayout()
mainLayout.addWidget(src_btn, 0, 0)
mainLayout.addWidget(dst_btn, 0, 1)
mainLayout.addWidget(prev_btn, 2, 0)
mainLayout.addWidget(x_copy_btn, 2, 1)
mainLayout.addWidget(self.src_line, 1, 0)
mainLayout.addWidget(self.dst_line, 1, 1)
mainLayout.addWidget(self.selected_files, 3, 0)
mainLayout.addWidget(switch_lbl, 0, 2)
mainLayout.addWidget(self.e_chk, 1, 2)
mainLayout.addWidget(self.c_chk, 2, 2)
mainLayout.addWidget(self.h_chk, 3, 2)
mainLayout.addWidget(self.y_chk, 4, 2)
mainLayout.addWidget(self.i_chk, 5, 2)
# mainLayout.addWidget(self.progress,4,0)
self.setLayout(mainLayout)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('X Copy 3.0')
self.show()
def src_select(self):
src_fldr = QtGui.QFileDialog.getExistingDirectory(self, 'Select Directory')
self.src_line.setText(src_fldr)
def dst_select(self):
dst_fldr = QtGui.QFileDialog.getExistingDirectory(self, 'Select Directory')
self.dst_line.setText(dst_fldr)
def list_files(self):
src_path = self.src_line.text()
for f in (os.listdir(src_path)):
self.selected_files.append(f)
def x_copy(self):
src_path = self.src_line.text()
dst_path = self.dst_line.text()
#print(src_path + ' plus ' + dst_path + ' plus ' + self.attr_check())
subprocess.call(['xcopy', src_path, dst_path, '/' + self.e_apply() + '/' +
self.c_apply() + '/' +
self.h_apply() + '/' +
self.y_apply() + '/' +
self.i_apply()])
def e_apply(self):
state = self.e_chk.checkState()
if state == 2:
return 'E'
else:
print('E not selected')
def c_apply(self):
state = self.e_chk.checkState()
if state == 2:
return 'C'
else:
print('C not selected')
def h_apply(self):
state = self.e_chk.checkState()
if state == 2:
return 'H'
else:
print('H not selected')
def y_apply(self):
state = self.e_chk.checkState()
if state == 2:
return 'Y'
else:
print('Y not selected')
def i_apply(self):
state = self.e_chk.checkState()
if state == 2:
return 'I'
else:
print('I not selected')
app = QtGui.QApplication(sys.argv)
mainWindow = XcopyMain()
status = app.exec_()
sys.exit(status)

The task that you have been able to implement can be done in a more elegant way. We can use the sender() function that returns the object that generates the signal
def chk_box_value(self, state):
k = '/'+self.sender().text()
if state == QtCore.Qt.Checked: # similar to 2
self.myList.append(k)
elif state == QtCore.Qt.Unchecked: # similar to 0
self.myList.remove(k)
Complete Code:
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
import os
import subprocess
class XcopyMain(QtGui.QWidget):
def __init__(self):
super(XcopyMain, self).__init__()
self.myList = []
# Declare Widgets
src_btn = QtGui.QPushButton('Source')
dst_btn = QtGui.QPushButton('Destination')
prev_btn = QtGui.QPushButton('Preview File(s)')
x_copy_btn = QtGui.QPushButton('Start XCOPY')
switch_lbl = QtGui.QLabel('Switches:')
# self.progress = QtGui.QProgressBar(self)
self.src_line = QtGui.QLineEdit()
self.dst_line = QtGui.QLineEdit()
self.selected_files = QtGui.QTextEdit()
self.E_chk = QtGui.QCheckBox('E')
self.E_chk.stateChanged.connect(self.chk_box_value)
self.C_chk = QtGui.QCheckBox('C')
self.C_chk.stateChanged.connect(self.chk_box_value)
self.H_chk = QtGui.QCheckBox('H')
self.H_chk.stateChanged.connect(self.chk_box_value)
self.Y_chk = QtGui.QCheckBox('Y')
self.Y_chk.stateChanged.connect(self.chk_box_value)
self.I_chk = QtGui.QCheckBox('I')
self.I_chk.stateChanged.connect(self.chk_box_value)
# Declare Emit / Slot
src_btn.clicked.connect(self.src_select)
dst_btn.clicked.connect(self.dst_select)
prev_btn.clicked.connect(self.list_files)
x_copy_btn.clicked.connect(self.x_copy)
# Declare Layout
mainLayout = QtGui.QGridLayout()
mainLayout.addWidget(src_btn, 0, 0)
mainLayout.addWidget(dst_btn, 0, 1)
mainLayout.addWidget(prev_btn, 2, 0)
mainLayout.addWidget(x_copy_btn, 2, 1)
mainLayout.addWidget(self.src_line, 1, 0)
mainLayout.addWidget(self.dst_line, 1, 1)
mainLayout.addWidget(self.selected_files, 3, 0)
mainLayout.addWidget(switch_lbl, 0, 2)
mainLayout.addWidget(self.E_chk, 1, 2)
mainLayout.addWidget(self.C_chk, 2, 2)
mainLayout.addWidget(self.H_chk, 3, 2)
mainLayout.addWidget(self.Y_chk, 4, 2)
mainLayout.addWidget(self.I_chk, 5, 2)
# mainLayout.addWidget(self.progress,4,0)
self.setLayout(mainLayout)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('X Copy 3.0')
self.show()
def src_select(self):
src_fldr = QtGui.QFileDialog.getExistingDirectory(self, 'Select Directory')
self.src_line.setText(src_fldr)
def dst_select(self):
dst_fldr = QtGui.QFileDialog.getExistingDirectory(self, 'Select Directory')
self.dst_line.setText(dst_fldr)
def list_files(self):
src_path = self.src_line.text()
for f in (os.listdir(src_path)):
self.selected_files.append(f)
def x_copy(self):
src_path = self.src_line.text()
dst_path = self.dst_line.text()
#print(src_path + ' plus ' + dst_path + ' plus ' + self.attr_check())
subprocess.call(['xcopy', src_path, dst_path, "".join(self.myList)])
def chk_box_value(self, state):
k = '/'+self.sender().text()
if state == QtCore.Qt.Checked:
self.myList.append(k)
elif state == QtCore.Qt.Unchecked:
self.myList.remove(k)
app = QtGui.QApplication(sys.argv)
mainWindow = XcopyMain()
status = app.exec_()
sys.exit(status)

I found a way to combine my checkbox value checks and run it through a loop.
import sys
from PyQt4 import QtGui
import os
import subprocess
class XcopyMain(QtGui.QWidget):
def __init__(self):
super(XcopyMain, self).__init__()
# Declare Widgets
src_btn = QtGui.QPushButton('Source')
dst_btn = QtGui.QPushButton('Destination')
prev_btn = QtGui.QPushButton('Preview File(s)')
x_copy_btn = QtGui.QPushButton('Start XCOPY')
switch_lbl = QtGui.QLabel('Switches:')
# self.progress = QtGui.QProgressBar(self)
self.src_line = QtGui.QLineEdit()
self.dst_line = QtGui.QLineEdit()
self.selected_files = QtGui.QTextEdit()
self.myList = []
self.E_chk = QtGui.QCheckBox('E')
self.E_chk.stateChanged.connect(self.chk_box_value)
self.C_chk = QtGui.QCheckBox('C')
self.C_chk.stateChanged.connect(self.chk_box_value)
self.H_chk = QtGui.QCheckBox('H')
self.H_chk.stateChanged.connect(self.chk_box_value)
self.Y_chk = QtGui.QCheckBox('Y')
self.Y_chk.stateChanged.connect(self.chk_box_value)
self.I_chk = QtGui.QCheckBox('I')
self.I_chk.stateChanged.connect(self.chk_box_value)
# Declare Emit / Slot
src_btn.clicked.connect(self.src_select)
dst_btn.clicked.connect(self.dst_select)
prev_btn.clicked.connect(self.list_files)
x_copy_btn.clicked.connect(self.x_copy)
# Declare Layout
mainLayout = QtGui.QGridLayout()
subLayout = QtGui.QHBoxLayout()
mainLayout.addWidget(src_btn, 0, 0)
mainLayout.addWidget(dst_btn, 0, 1)
mainLayout.addWidget(prev_btn, 2, 0)
mainLayout.addWidget(x_copy_btn, 2, 1)
mainLayout.addWidget(self.src_line, 1, 0)
mainLayout.addWidget(self.dst_line, 1, 1)
mainLayout.addWidget(self.selected_files, 3, 0, 1, 2)
#mainLayout.addWidget(switch_lbl, 0, 2)
subLayout.addWidget(self.E_chk)
subLayout.addWidget(self.C_chk)
subLayout.addWidget(self.H_chk)
subLayout.addWidget(self.Y_chk)
subLayout.addWidget(self.I_chk)
# Declare ToolTips
QtGui.QToolTip.setFont(QtGui.QFont('SansSerif', 10))
#self.setToolTip('This switch does XXX')
self.E_chk.setToolTip('Copies directories and subdirectories, including empty ones.')
self.C_chk.setToolTip('Continues copying even if errors occur.')
self.H_chk.setToolTip('Copies hidden and system files also.')
self.Y_chk.setToolTip('Suppresses prompting to confirm you want to overwrite an existing destination file.')
self.I_chk.setToolTip('If destination does not exist and copying more than one file, assumes that destination must be a directory.')
mainLayout.addLayout(subLayout, 5, 0, 1, 5)
# mainLayout.addWidget(self.progress,4,0)
self.setLayout(mainLayout)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('X Copy 3.0')
self.show()
def src_select(self):
src_fldr = QtGui.QFileDialog.getExistingDirectory(self, 'Select Directory')
self.src_line.setText(src_fldr)
def dst_select(self):
dst_fldr = QtGui.QFileDialog.getExistingDirectory(self, 'Select Directory')
self.dst_line.setText(dst_fldr)
def list_files(self):
src_path = self.src_line.text()
for f in (os.listdir(src_path)):
self.selected_files.append(f)
def x_copy(self):
src_path = self.src_line.text()
dst_path = self.dst_line.text()
#print(src_path + ' plus ' + dst_path + ' plus ' + "".join(self.myList))
subprocess.call(['xcopy', src_path, dst_path, "".join(self.myList)])
#
def chk_box_value(self):
letter = ['/E', '/C', '/H', '/Y', '/I']
value = [self.E_chk.checkState(),
self.C_chk.checkState(),
self.H_chk.checkState(),
self.Y_chk.checkState(),
self.I_chk.checkState()]
dictionary = dict(zip(letter, value))
for k, v in dictionary.items():
if v == 2 and k not in self.myList:
self.myList.append(k)
elif v == 0 and k in self.myList:
self.myList.remove(k)
app = QtGui.QApplication(sys.argv)
mainWindow = XcopyMain()
status = app.exec_()
sys.exit(status)

Related

Python pandas The function "iterrow" isn't really working on this, when I load a csv file

I would like to load a file and runs it as well as I can run when it's recorded.
That's a recorder for mouse and keyboard together, there's the open code link: (you can run that for testing)
I already validated the buttons.setDisabled to display False or True for not returning else errors
I rather to solve the load file problem
I can't run my loaded file
If you guys have a better answer, don't be ashemed of sharing it. Wish you can help me
> # there goes the MAIN open source CODE which mine is based on
import sys
from time import sleep
import pandas as pd
from pynput import mouse, keyboard
from PyQt5.QtWidgets import (QApplication, QWidget, QPushButton,
QDesktopWidget, QGridLayout, QLabel,
QSpinBox, QFileDialog,
QTableWidget, QTableWidgetItem)
from PyQt5.QtGui import QColor
from PyQt5.QtCore import Qt
class App(QWidget):
def __init__(self, df=None):
super().__init__()
self.title = 'Clicker'
self.width = 800
self.height = 600
if df is None:
self.keyEvents = pd.DataFrame(columns=['Type', 'Button', 'Coordinates', 'WaitTime'])
else:
self.keyEvents = df
self.runTimes = 1
self.skipFirst = 0
self.mouseWait = 300
self.keyWait = 200
self.mListener = mouse.Listener(on_click=self.on_click)
self.kListener = keyboard.Listener(on_press=self.on_press, on_release=self.on_release)
self.initUI()
def initUI(self):
grid = QGridLayout()
grid.setRowStretch(12,1)
grid.setColumnStretch(4,1)
self.setLayout(grid)
self.recordButton = QPushButton('Start recording')
grid.addWidget(self.recordButton, 0, 0)
self.recordButton.clicked.connect(self.start_record)
self.recordLabel = QLabel('')
grid.addWidget(self.recordLabel, 0, 1)
self.stopButton = QPushButton('Stop/pause\nrecording')
grid.addWidget(self.stopButton, 1, 0)
self.stopButton.clicked.connect(self.stop_record)
self.playButton = QPushButton('Run')
grid.addWidget(self.playButton, 2, 0)
self.playButton.clicked.connect(self.play)
self.playBox = QSpinBox()
grid.addWidget(self.playBox, 3, 1)
self.playBox.setMinimum(1)
self.playBox.setMaximum(1313)
self.playBox.setValue(self.runTimes)
self.playBox.valueChanged.connect(self.runTimes_update)
grid.addWidget(QLabel('Run the commands .. times'), 3, 0)
grid.addWidget(QLabel('Do not include the first ..\n'
'commands when running\n'
'multiple times'), 4, 0)
self.skipBox = QSpinBox()
grid.addWidget(self.skipBox, 4, 1)
self.skipBox.setMinimum(0)
self.skipBox.setMaximum(0)
self.skipBox.setValue(self.skipFirst)
self.skipBox.valueChanged.connect(self.skipFirst_update)
grid.addWidget(QLabel('Default wait-time for\nmouseclicks'), 5, 0)
grid.addWidget(QLabel('ms'), 5, 2)
self.mouseBox = QSpinBox()
grid.addWidget(self.mouseBox, 5, 1)
self.mouseBox.setMinimum(0)
self.mouseBox.setMaximum(100000)
self.mouseBox.setSingleStep(50)
self.mouseBox.setValue(self.mouseWait)
self.mouseBox.valueChanged.connect(self.mouseWait_update)
grid.addWidget(QLabel('Default wait-time for\nkeyboard inputs'), 6, 0)
grid.addWidget(QLabel('ms'), 6, 2)
self.keyBox = QSpinBox()
grid.addWidget(self.keyBox, 6, 1)
self.keyBox.setMinimum(0)
self.keyBox.setMaximum(100000)
self.keyBox.setSingleStep(50)
self.keyBox.setValue(self.keyWait)
self.keyBox.valueChanged.connect(self.keyWait_update)
self.emptyButton = QPushButton('Delete all data')
grid.addWidget(self.emptyButton, 8, 0)
self.emptyButton.clicked.connect(self.empty_events)
self.emptyButton2 = QPushButton('Delete row:')
self.emptyButton2.setToolTip('Deletes this row number when pressed')
grid.addWidget(self.emptyButton2, 9, 0)
self.emptyButton2.clicked.connect(self.del_row)
self.delBox = QSpinBox()
grid.addWidget(self.delBox, 9, 1)
self.delBox.setMinimum(1)
self.saveButton = QPushButton('Save')
grid.addWidget(self.saveButton, 11, 0)
self.saveButton.clicked.connect(self.file_save)
self.loadButton = QPushButton('Load')
grid.addWidget(self.loadButton, 12, 0)
self.loadButton.clicked.connect(self.file_load)
self.table = QTableWidget(1, len(self.keyEvents.columns))
self.table.setHorizontalHeaderLabels(self.keyEvents.columns)
self.table.itemSelectionChanged.connect(self.change_table)
grid.addWidget(self.table, 0, 4, 12, 1)
self.update_table()
grid.addWidget(QLabel('Select another cell after changing a wait-time '
'otherwise it will not be registered!'), 12, 4)
self.setWindowTitle(self.title)
self.resize(self.width, self.height)
self.center()
self.show()
def keyWait_update(self):
oldV = self.keyWait
self.keyWait = self.keyBox.value()
for i, row in self.keyEvents.iterrows():
if (not type(row.Coordinates) is tuple and
row.WaitTime == oldV/1000 and
row.Type == 'Press'):
self.keyEvents.loc[i, 'WaitTime'] = self.keyWait/1000
self.update_table()
def mouseWait_update(self):
oldV = self.mouseWait
self.mouseWait = self.mouseBox.value()
for i, row in self.keyEvents.iterrows():
if (type(row.Coordinates) is tuple and
row.WaitTime == oldV/1000 and
row.Type == 'Press'):
self.keyEvents.loc[i, 'WaitTime'] = self.mouseWait/1000
self.update_table()
def file_save(self):
options = QFileDialog.Options()
options |= QFileDialog.DontUseNativeDialog
fileName, _ = QFileDialog.getSaveFileName(self,"QFileDialog.getSaveFileName()","","All Files (*);;CSV Files (*.csv)", options=options)
if fileName:
self.keyEvents.to_csv(fileName if fileName.endswith('.csv') else
fileName+'.csv', index=False)
def file_load(self):
options = QFileDialog.Options()
options |= QFileDialog.DontUseNativeDialog
files, _ = QFileDialog.getOpenFileNames(self,"QFileDialog.getOpenFileNames()", "","All Files (*);;CSV Files (*.csv)", options=options)
if len(files) == 1 and files[0].endswith('.csv'):
self.keyEvents = pd.read_csv(files[0])
self.update_table()
def change_table(self):
for i, row in self.keyEvents.iterrows():
self.keyEvents.loc[i, 'WaitTime'] = float(self.table.item(i, 3).text())
def center(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
def start_record(self):
self.recordLabel.setText('<font color="red"><b>Rec.</b></font>')
self.mListener.start()
self.kListener.start()
def stop_record(self):
if self.mListener.running or self.kListener.running:
self.recordLabel.setText('')
self.mListener.stop()
self.kListener.stop()
self.mListener = mouse.Listener(on_click=self.on_click)
self.kListener = keyboard.Listener(on_press=self.on_press, on_release=self.on_release)
self.keyEvents = self.keyEvents.iloc[:-2]
self.update_table()
def runTimes_update(self):
self.runTimes = self.playBox.value()
def skipFirst_update(self):
self.skipFirst = self.skipBox.value()
self.update_table()
def play(self):
if len(self.keyEvents) == 0:
print('There are no logged clicks/keypresses!')
self.runLabel.setText('')
return
if self.mListener.running or self.kListener.running:
self.stop_record()
kController = keyboard.Controller()
mController = mouse.Controller()
for run in range(self.runTimes):
rows = self.keyEvents[self.skipFirst:]
if run == 0:
rows = self.keyEvents
for i, row in rows.iterrows():
sleep(row.WaitTime)
if type(row.Coordinates) is tuple:
mController.position = row.Coordinates
if row.Type == 'Press':
mController.press(row.Button)
elif row.Type == 'Release':
mController.release(row.Button)
else:
if row.Type == 'Press':
kController.press(row.Button)
elif row.Type == 'Release':
kController.release(row.Button)
def empty_events(self):
if self.mListener.running or self.kListener.running:
self.stop_record()
self.keyEvents = self.keyEvents.iloc[0:0]
self.update_table()
def del_row(self):
self.keyEvents = self.keyEvents.drop(self.delBox.value()-1)
self.keyEvents = self.keyEvents.reset_index(drop=True)
self.update_table()
def on_click(self, x, y, button, pressed):
self.keyEvents = self.keyEvents.append(
{'Type': 'Press' if pressed else 'Release',
'Coordinates': (x, y),
'Button': button,
'WaitTime': self.mouseWait/1000 if pressed else 0
}, ignore_index=True)
def on_press(self, key):
self.keyEvents = self.keyEvents.append(
{'Type': 'Press',
'Button': key,
'WaitTime': self.keyWait/1000
}, ignore_index=True)
def on_release(self, key):
self.keyEvents = self.keyEvents.append(
{'Type': 'Release',
'Button': key,
'WaitTime': 0
}, ignore_index=True)
def update_table(self):
self.skipBox.setMaximum(max(0, len(self.keyEvents)-1))
self.delBox.setMaximum(max(1, len(self.keyEvents)))
self.table.setRowCount(len(self.keyEvents))
for i, row in self.keyEvents.iterrows():
for j, data in enumerate(row):
item = QTableWidgetItem(str(data))
if j != 3:
item.setFlags(Qt.ItemIsEnabled)
color = QColor(255,255,255)
if i < self.skipFirst:
color = QColor(255,0,0)
item.setBackground(color)
self.table.setItem(i, j, item)
def closeEvent(self, event):
self.stop_record()
event.accept()
if __name__ == '__main__':
if not QApplication.instance():
app = QApplication(sys.argv)
else:
app = QApplication.instance()
ex = App()
app.exec_()

Delete dynamically create buttons in PyQt5

I have created a button who creates buttons in a vertical layout, called "elementos". In each row, there is a label and a X button who should delete the row. There is a list with the text of the label called "puntos" MRE:
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QOpenGLWidget
import sys
from sys import argv, exit
class Renderizador(QOpenGLWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.puntos = []
self.num_elementos = 0
def borrar_punto(self):
self.puntos.pop()
ui.elementos.removeWidget(self.name)
ui.elementos.removeWidget(self.borrar)
self.name.deleteLater()
self.borrar.deleteLater()
self.num_elementos -= 1
def crear_punto(self):
do = ui.valor_do.value()
cota = ui.valor_cota.value()
alejamiento = ui.valor_alej.value()
self.puntos.append((ui.nombre.toPlainText(), do, cota, alejamiento))
self.name = QtWidgets.QLabel()
self.name.setText(ui.nombre.toPlainText() + "({}, {}, {})".format(do, cota, alejamiento))
self.borrar = QtWidgets.QPushButton()
self.borrar.setText("X")
self.borrar.clicked.connect(lambda: self.borrar_punto())
ui.elementos.addWidget(self.name, self.num_elementos, 0, 1, 1)
ui.elementos.addWidget(self.borrar, self.num_elementos, 1, 1, 1)
self.num_elementos += 1
self.update()
class UiVentana:
def __init__(self):
ventana.resize(1500, 1000)
ventana.setLayoutDirection(QtCore.Qt.LeftToRight)
ventana.setFixedSize(ventana.size())
self.widget_central = QtWidgets.QWidget(ventana)
self.gridLayoutWidget = QtWidgets.QWidget(self.widget_central)
self.gridLayoutWidget.setGeometry(QtCore.QRect(1000, 60, 280, 50))
self.Vistas = QtWidgets.QGridLayout(self.gridLayoutWidget)
self.Visor = Renderizador(self.widget_central)
self.Visor.setGeometry(QtCore.QRect(0, 0, 1000, 1000))
self.gridLayoutWidget_2 = QtWidgets.QWidget(self.widget_central)
self.gridLayoutWidget_2.setGeometry(QtCore.QRect(1004, 105, 300, 400))
self.Punto = QtWidgets.QGridLayout(self.gridLayoutWidget_2)
self.Punto.setContentsMargins(5, 5, 5, 5)
self.Punto.setVerticalSpacing(4)
self.texto_nombre = QtWidgets.QLabel(self.gridLayoutWidget_2)
self.texto_nombre.setText("Nombre:")
self.Punto.addWidget(self.texto_nombre, 3, 0, 1, 1)
self.crear_punto = QtWidgets.QPushButton(self.gridLayoutWidget_2)
self.crear_punto.setText("Crear")
self.crear_punto.clicked.connect(self.Visor.crear_punto)
self.Punto.addWidget(self.crear_punto, 3, 2, 1, 1)
self.texto_cota = QtWidgets.QLabel(self.gridLayoutWidget_2)
self.nombre = QtWidgets.QTextEdit(self.gridLayoutWidget_2)
self.nombre.setMaximumSize(QtCore.QSize(100, 24))
self.Punto.addWidget(self.nombre, 3, 1, 1, 1)
self.scroll = QtWidgets.QScrollArea()
self.scroll.setWidgetResizable(True)
self.scroll_widget = QtWidgets.QWidget()
self.scroll_widget.resize(200, 300)
self.elementos_widget = QtWidgets.QWidget()
self.vbox = QtWidgets.QVBoxLayout(self.scroll_widget)
self.vbox.setContentsMargins(0, 0, 0, 0)
self.vbox.addWidget(self.elementos_widget)
self.vbox.addStretch()
self.elementos = QtWidgets.QGridLayout()
self.elementos_widget.setLayout(self.elementos)
self.scroll.setWidget(self.scroll_widget)
self.scroll_widget.setLayout(self.elementos)
self.scroll.setWidget(self.scroll_widget)
self.Punto.addWidget(self.scroll, 4, 0, 1, 3)
self.valor_do = QtWidgets.QSpinBox(self.gridLayoutWidget_2)
self.Punto.addWidget(self.valor_do, 2, 0, 1, 1)
self.valor_alej = QtWidgets.QSpinBox(self.gridLayoutWidget_2)
self.Punto.addWidget(self.valor_alej, 2, 1, 1, 1)
self.valor_cota = QtWidgets.QSpinBox(self.gridLayoutWidget_2)
self.Punto.addWidget(self.valor_cota, 2, 2, 1, 1)
ventana.setCentralWidget(self.widget_central)
ventana.show()
def except_hook(cls, exception, traceback):
sys.__excepthook__(cls, exception, traceback)
if __name__ == "__main__":
app = QtWidgets.QApplication(argv)
ventana = QtWidgets.QMainWindow()
ui = UiVentana()
sys.excepthook = except_hook
exit(app.exec_())
The pop statement should delete from the list the corresponding info about the label. I get an out of index range error, but i get a "RuntimeError: wrapped C/C++ object of type QLabel has been deleted" error if I pop the last statement.
Full code: https://github.com/Jaime02/Proyecto-de-investigacion-2019-Dibujo-tecnico/blob/experimental/error (Lines 120-140)
Edit: The delete button only works once if two or more rows are created
Your code has at least the following errors:
If you are going to create an object within a loop, do not make it a member, for example in your case self.name and self.borrar are variables that will always point to the last QLabel and QPushButton, so when you delete only the last row will be deleted in a single occasion.
Your code is very messy since they are modifying variables in places where they are not due as they could cause problems such as tracking errors, for example the variable window and ui.
Considering the above I have rewritten your code implementing the logic of passing the widgets and deleting the widgets directly.
import sys
from functools import partial
from PyQt5 import QtCore, QtGui, QtWidgets
class UiVentana(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(UiVentana, self).__init__(parent)
self.puntos = []
self.visor = QtWidgets.QOpenGLWidget()
self.valor_do = QtWidgets.QSpinBox()
self.valor_cota = QtWidgets.QSpinBox()
self.valor_alej = QtWidgets.QSpinBox()
self.texto_nombre = QtWidgets.QLabel("Nombre")
self.nombre = QtWidgets.QLineEdit()
self.crear_punto = QtWidgets.QPushButton("Crear", clicked=self.crear_punto)
elementos_widget = QtWidgets.QWidget()
scroll_widget = QtWidgets.QWidget()
scroll = QtWidgets.QScrollArea(widgetResizable=True)
scroll.setWidget(scroll_widget)
vbox = QtWidgets.QVBoxLayout(scroll_widget)
vbox.addWidget(elementos_widget)
vbox.addStretch()
self.elementos = QtWidgets.QGridLayout(elementos_widget)
grid_layout = QtWidgets.QGridLayout()
grid_layout.addWidget(self.valor_do, 0, 0)
grid_layout.addWidget(self.valor_cota, 0, 1)
grid_layout.addWidget(self.valor_alej, 0, 2)
grid_layout.addWidget(self.texto_nombre, 1, 0)
grid_layout.addWidget(self.nombre, 1, 1)
grid_layout.addWidget(self.crear_punto, 1, 2)
grid_layout.addWidget(scroll, 2, 0, 1, 3)
for i in range(3):
grid_layout.setColumnStretch(i, 1)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
lay = QtWidgets.QHBoxLayout(central_widget)
lay.addWidget(self.visor, stretch=1)
lay.addLayout(grid_layout)
self.resize(1280, 960)
def crear_punto(self):
do = self.valor_do.value()
cota = self.valor_cota.value()
alejamiento = self.valor_alej.value()
name = QtWidgets.QLabel(
"{}({}, {}, {})".format(self.nombre.text(), do, cota, alejamiento)
)
punto = (self.nombre.text(), do, cota, alejamiento)
borrar = QtWidgets.QPushButton("X")
wrapper = partial(self.borrar_punto, (name, borrar), punto)
borrar.clicked.connect(wrapper)
row = self.elementos.rowCount()
self.elementos.addWidget(name, row, 0)
self.elementos.addWidget(borrar, row, 1)
self.puntos.append(punto)
def borrar_punto(self, widgets, punto):
if self.puntos:
name, borrar = widgets
name.deleteLater()
borrar.deleteLater()
self.puntos.remove(punto)
print(self.puntos)
def except_hook(cls, exception, traceback):
sys.__excepthook__(cls, exception, traceback)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
sys.excepthook = except_hook
w = UiVentana()
w.show()
exit(app.exec_())

How can I make a QWidget open after a QWidget closes?

I have the below code:
import os
from functools import partial
import numpy as np
from PyQt5 import QtCore, QtWidgets
class MainWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.resize(500, 500)
self.setWindowFlags(
self.windowFlags() | QtCore.Qt.MSWindowsFixedSizeDialogHint
)
self.setWindowTitle("nCode analysis set-up")
self.wait_window = WaitWindow()
thread = QtCore.QThread(self)
thread.start()
self.m_worker = Worker()
self.m_worker.moveToThread(thread)
self.m_worker.new_content_signal.connect(self.get_content)
# Creating the top level grid layout
mainGrid = QtWidgets.QGridLayout(self)
self.analysis_type_label = QtWidgets.QLabel(self)
self.analysis_type_label.setText("Type of analysis")
mainGrid.addWidget(self.analysis_type_label, 0, 0)
self.analysis_type_combo = QtWidgets.QComboBox(self)
self.analysis_type_combo.addItems(["Fatigue", "Proof plus fatigue"])
mainGrid.addWidget(self.analysis_type_combo, 0, 1, 1, 2)
self.load_deck_type_label = QtWidgets.QLabel(self)
self.load_deck_type_label.setText("Type of fatigue deck")
mainGrid.addWidget(self.load_deck_type_label, 1, 0)
self.load_deck_type_combo = QtWidgets.QComboBox(self)
self.load_deck_type_combo.addItems(
["Regen braking", "No regen braking"]
)
mainGrid.addWidget(self.load_deck_type_combo, 1, 1, 1, 2)
self.analysis_engine_type_label = QtWidgets.QLabel(self)
self.analysis_engine_type_label.setText("Analysis Engine")
mainGrid.addWidget(self.analysis_engine_type_label, 2, 0)
self.analysis_engine_type_combo = QtWidgets.QComboBox(self)
self.analysis_engine_type_combo.addItems(["EN analysis", "SN analysis"])
mainGrid.addWidget(self.analysis_engine_type_combo, 2, 1, 1, 2)
# Creating a scrolable area to accommodate for a large number of components with possible lenghty names
self.scrollArea = QtWidgets.QScrollArea(self)
# The line below is absolutely required to make the scrollable area work.
self.scrollArea.setWidgetResizable(True)
mainGrid.addWidget(self.scrollArea, 3, 0, 1, 3)
self.secondaryWidget = QtWidgets.QWidget()
self.scrollArea.setWidget(self.secondaryWidget)
self.secondaryGrid = QtWidgets.QGridLayout(self.secondaryWidget)
self.createDCL = QtWidgets.QPushButton(self)
self.createDCL.setText("Create DCL")
mainGrid.addWidget(self.createDCL, 4, 0, 1, 3)
def start_task(self):
if not os.path.exists("loading_database.db"):
QtWidgets.QMessageBox.information(
None,
"Loading database missing",
"Loading database has not been found. Creation of a new one will be attempted",
)
# self.loadingDatabaseCreator()
QtWidgets.QMessageBox.information(
None, "Successful", "Loading database succesfully created"
)
filePath, _ = QtWidgets.QFileDialog.getOpenFileName(
None, "Select input model", "", "Input deck (*.inp)", "*.inp"
)
if filePath:
self.wait_window.show()
self.m_worker.finished.connect(self.wait_window.close)
wrapper = partial(self.m_worker.read_file, filePath)
# Launch the task in a reasonable time for the window to show
QtCore.QTimer.singleShot(100, wrapper)
w.show()
self.wait_window.raise_()
self.wait_window.activateWindow()
#QtCore.pyqtSlot(int, str)
def get_content(self, i, content):
label = QtWidgets.QLabel("{} material".format(content))
linedit = QtWidgets.QLineEdit(placeholderText="Drop material name here")
linedit.setFixedWidth(150)
button = QtWidgets.QPushButton("Pick material")
self.secondaryGrid.addWidget(label, 2 + i, 0)
self.secondaryGrid.addWidget(linedit, 2 + i, 1)
self.secondaryGrid.addWidget(button, 2 + i, 2)
class WaitWindow(QtWidgets.QDialog):
def __init__(self):
super().__init__()
self.setWindowTitle("Info")
self.resize(600, 200)
layout = QtWidgets.QVBoxLayout(self)
self.message = QtWidgets.QLabel()
self.message.setFixedWidth(550)
self.message.setText("Please wait while input file is being read")
layout.addWidget(self.message)
class Worker(QtCore.QObject):
finished = QtCore.pyqtSignal()
new_content_signal = QtCore.pyqtSignal(int, str)
#QtCore.pyqtSlot(str)
def read_file(self, fileName):
i = 0
collector_array = []
with open(fileName, "r") as model_file_obj:
for line in model_file_obj.readlines():
if "*ELEMENT," in line and "DCOUP3D" not in line:
t = line.split("ELSET=")[1][:-1]
if t not in collector_array:
self.new_content_signal.emit(i, t)
QtCore.QThread.msleep(10)
collector_array.append(t)
i += 1
self.finished.emit()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWidget()
w.start_task()
sys.exit(app.exec_())
It looks like a lot of code but the MainWidget is initialized first. After the initialization the MainWidget function of start_task is called which show's the WaitWindow QDialog, asks the user for the input file which it starts parsing and then shows the MainWidget QWidget window. While this is not too bad I would like the user to not see the MainWidget window until the file has finished parsing and the WaitWindow is closed. Any ideas?
I do not understand why you use w.show(), remove it.
Going to the problem, if you want the MainWidget to show after executing the task, you just have to connect the show method to the finished signal
# ...
self.m_worker.finished.connect(self.wait_window.close)
self.m_worker.finished.connect(self.show)
# ...

QlineEdit and signal & slot

I have created a widget with QLineEdit and QLabel, I want to get input from QlineEdit and display it with QLabel. I have used Signal and Slot connection, I do not know what I do wrong, but it is not working correctly. I would like to get both values from QLineEdit and later show it.
Current window
what I want?
Code:
import os
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class WinDialog(QtWidgets.QDialog):
currenttextedited = QtCore.pyqtSignal(int)
def __init__(self, parent=None):
super(WinDialog, self).__init__(parent)
self.setGeometry(300,300,350,300)
self.setWindowTitle("Signal & Slot")
self.propertyWidget = PropertyWidget()
section_lay = QtWidgets.QHBoxLayout()
section_label = QtWidgets.QLabel("Name: ")
section_edit = QtWidgets.QLineEdit('')
length_lay = QtWidgets.QHBoxLayout()
length_label = QtWidgets.QLabel("Input a number: L = ")
self.length_edit = QtWidgets.QLineEdit('1000')
self.length_edit.setInputMask("999999")
self.length_edit.setFocus(True)
thick_lay = QtWidgets.QHBoxLayout()
thick_label = QtWidgets.QLabel("Input a text: T = ")
thick_edit = QtWidgets.QLineEdit('')
section_lay.addWidget(section_label)
section_lay.addWidget(section_edit)
length_lay.addWidget(length_label)
length_lay.addWidget(self.length_edit)
length_lay.addStretch()
thick_lay.addWidget(thick_label)
thick_lay.addWidget(thick_edit)
thick_lay.addStretch()
VB_lay = QtWidgets.QVBoxLayout()
VB_lay.addStretch()
VB_lay.addLayout(length_lay)
VB_lay.addLayout(thick_lay)
VB_lay.addStretch()
buttonBox = QtWidgets.QDialogButtonBox()
buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel
|QtWidgets.QDialogButtonBox.Ok)
buttonBox.accepted.connect(self.accept)
buttonBox.rejected.connect(self.reject)
grid = QtWidgets.QGridLayout(self)
grid.addLayout(section_lay, 0, 0, 1, 2)
grid.addLayout(VB_lay, 1, 0)
grid.addWidget(self.propertyWidget, 2, 0)
grid.addWidget(buttonBox, 3, 0, 1, 2)
self.length_edit.textEdited.connect(self.textchanged)
def textchanged(self, text):
print(text)
self.currenttextedited.emit(text)
class PropertyWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(PropertyWidget, self).__init__(parent)
HB_lay = QtWidgets.QHBoxLayout(self)
self.Displaylabel = QtWidgets.QLabel('')
HB_lay.addWidget(self.Displaylabel)
HB_lay.addStretch()
#QtCore.pyqtSlot(int)
def Display(self, text):
try:
L_Display = int(text)
T_Display = int(text)
fmt = "L = {}mm\nT = {}mm"
self.Displaylabel.setText(fmt.format(L_Display, T_Display))
except ValueError:
print("Error")
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = WinDialog()
w.show()
sys.exit(app.exec_())
according to samples in the image you want to show different texts but you are converting the same number to whole: L_Display = int(text) and T_Display = int(text) so how do you expect to show 2 different texts?, obviously the function display needs 2 entries (2 different entries to self plus I have changed to lowercase since it is recommended that the functions have a lowercase name).
Now the logic is as follows: if any of the texts of length_edit or thick_edit changes then you must call display() passing the new texts. So the solution is to use a slot that connects to the textEdited signals of both QLineEdits and in it obtain the text and pass the texts.
Finally I see that you want the QLineEdits receive only numbers so one option is to use a QIntValidator so that only numbers are acceptable (another better option is to use QSpinBox instead of QLineEdit)
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class WinDialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(WinDialog, self).__init__(parent)
self.setGeometry(300,300,350,300)
self.setWindowTitle("Signal & Slot")
self.propertyWidget = PropertyWidget()
section_lay = QtWidgets.QHBoxLayout()
section_label = QtWidgets.QLabel("Name: ")
section_edit = QtWidgets.QLineEdit('')
length_lay = QtWidgets.QHBoxLayout()
length_label = QtWidgets.QLabel("Input a number: L = ")
self.length_edit = QtWidgets.QLineEdit()
self.length_edit.setFocus(True)
val_lenght = QtGui.QIntValidator(0, 100000, self.length_edit)
self.length_edit.setValidator(val_lenght)
thick_lay = QtWidgets.QHBoxLayout()
thick_label = QtWidgets.QLabel("Input a text: T = ")
self.thick_edit = QtWidgets.QLineEdit()
val_thick = QtGui.QIntValidator(0, 100000, self.thick_edit)
self.thick_edit.setValidator(val_thick)
section_lay.addWidget(section_label)
section_lay.addWidget(section_edit)
length_lay.addWidget(length_label)
length_lay.addWidget(self.length_edit)
length_lay.addStretch()
thick_lay.addWidget(thick_label)
thick_lay.addWidget(self.thick_edit)
thick_lay.addStretch()
VB_lay = QtWidgets.QVBoxLayout()
VB_lay.addStretch()
VB_lay.addLayout(length_lay)
VB_lay.addLayout(thick_lay)
VB_lay.addStretch()
buttonBox = QtWidgets.QDialogButtonBox()
buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel
| QtWidgets.QDialogButtonBox.Ok)
buttonBox.accepted.connect(self.accept)
buttonBox.rejected.connect(self.reject)
grid = QtWidgets.QGridLayout(self)
grid.addLayout(section_lay, 0, 0, 1, 2)
grid.addLayout(VB_lay, 1, 0)
grid.addWidget(self.propertyWidget, 2, 0)
grid.addWidget(buttonBox, 3, 0, 1, 2)
self.length_edit.textEdited.connect(self.onTextEdited)
self.thick_edit.textEdited.connect(self.onTextEdited)
def onTextEdited(self):
l = self.length_edit.text()
t = self.thick_edit.text()
self.propertyWidget.display(l, t)
class PropertyWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(PropertyWidget, self).__init__(parent)
HB_lay = QtWidgets.QHBoxLayout(self)
self.Displaylabel = QtWidgets.QLabel('')
HB_lay.addWidget(self.Displaylabel)
HB_lay.addStretch()
def display(self, l, t):
try:
L_Display = int(l)
T_Display = int(t)
fmt = "L = {}mm\nT = {}mm"
self.Displaylabel.setText(fmt.format(L_Display, T_Display))
except ValueError:
self.Displaylabel.clear()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = WinDialog()
w.show()
sys.exit(app.exec_())

Refreshing Dialog of QLabel in PyQt

I am testing the updating of Qlabel. I basically have question displaying in random order, but the old text of the label still displays and combines with the new text. I am not sure how to clear it out between 'OK' clicks.
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
import random
class GameDialog(QDialog):
def __init__(self):
QDialog.__init__(self)
layout = QGridLayout()
lblWBS = QLabel("lblWBS")
lblDialog = QLabel("lblDialog")
btnOK = QPushButton("OK")
layout.addWidget(btnOK, 5, 1)
def randomOptions():
rdmOpt = [2,3,4]
random.shuffle(rdmOpt)
optGreen = QRadioButton()
optYellow = QRadioButton()
optRed = QRadioButton()
lblGreen = QLabel("Green")
lblYellow = QLabel("Yellow")
lblRed = QLabel("Red")
layout.addWidget(lblWBS, 0, 1)
layout.addWidget(lblDialog, 1, 1)
layout.addWidget(optGreen, rdmOpt[0], 0)
layout.addWidget(lblGreen, rdmOpt[0], 1)
layout.addWidget(optYellow, rdmOpt[1], 0)
layout.addWidget(lblYellow, rdmOpt[1], 1)
layout.addWidget(optRed, rdmOpt[2], 0)
layout.addWidget(lblRed, rdmOpt[2], 1)
self.setLayout(layout)
randomOptions()
btnOK.clicked.connect(randomOptions)
self.setWindowTitle("PALCDMS")
app = QApplication(sys.argv)
dialog = GameDialog()
dialog.show()
app.exec_()
The way to implement your idea you have errors, since you are creating new objects.
You should Save a list of the widgets that will change position and remove them with removeWidget() before making the changes, and then put them back in the layout.
class GameDialog(QDialog):
def __init__(self):
QDialog.__init__(self)
layout = QGridLayout(self)
lblWBS = QLabel("lblWBS")
lblDialog = QLabel("lblDialog")
btnOK = QPushButton("OK")
layout.addWidget(btnOK, 5, 1)
optGreen = QRadioButton()
optYellow = QRadioButton()
optRed = QRadioButton()
lblGreen = QLabel("Green")
lblYellow = QLabel("Yellow")
lblRed = QLabel("Red")
layout.addWidget(lblWBS, 0, 1)
layout.addWidget(lblDialog, 1, 1)
l = [optGreen, lblGreen, optYellow, lblYellow, optRed, lblRed]
def randomOptions():
for w in l:
layout.removeWidget(w)
rdmOpt = [2,3,4]
random.shuffle(rdmOpt)
for i in range(len(l)):
layout.addWidget(l[i], rdmOpt[i//2], i % 2)
randomOptions()
btnOK.clicked.connect(randomOptions)
self.setWindowTitle("PALCDMS")

Categories