I'm currently having a project that opens a Main Window and then opens the second window upon clicking a button. The Main window class is fine and is able to call the functions inside it while the second window can still show it's UI but can't call it's functions(button in the second window is not calling the function it's supposed to call). Is there something I missed?
class MainWindow():
def __init__(self, dlg):
self.dlg = dlg
dlg.setWindowFlags(QtCore.Qt.WindowMinimizeButtonHint | QtCore.Qt.WindowCloseButtonHint)
dlg.systemBase.setText(make_prefix(Sbase)+"VA")
dlg.comboBox.currentTextChanged.connect(self.Calc)
dlg.comboBox.addItem(str(380.00/1e3))
dlg.comboBox.addItem(str(400.00/1e3))
dlg.comboBox.addItem(str(220.00/1e3))
dlg.lineEdit_3.setPlaceholderText("Accepts 1-10")
dlg.lineEdit_3.setValidator(QIntValidator(1,10))
dlg.lineEdit_3.textChanged.connect(self.disableButton)
dlg.comboBox_2.addItem("Single Phase")
dlg.comboBox_2.addItem("3 Phase")
dlg.pushButton_3.setDisabled(True)
dlg.pushButton_3.clicked.connect(self.selectPhase)
dlg.lineEdit_3.setFocus()
dlg.lineEdit_3.returnPressed.connect(self.selectPhase)
dlg.show()
app.exec()
def Calc(self):
Vbase=float(self.dlg.comboBox.currentText())
currentBase = ((Sbase)/ (math.sqrt(3) * (Vbase*1e3)))
dlg.currentBase.setText(str(make_prefix(currentBase))+"A")
baseImpedance = (((Vbase*1e3)*(Vbase*1e3)) / (Sbase))
dlg.baseImpedance.setText(str(make_prefix(baseImpedance))+" p.u.")
def selectPhase(self):
Nbus = dlg.lineEdit_3.text()
if Nbus == "1":
self.SW = uic.loadUi("try1.ui")
SecondWindow(self.SW) #calling the second window
else:
print("try again")
print(int(Nbus))
if self.dlg.comboBox_2.currentText() == "Single Phase":
print("u selected single phase")
else:
print("u selected 3 phase")
def disableButton(self):
if len(self.dlg.lineEdit_3.text()) > 0:
dlg.pushButton_3.setDisabled(False)
else:
dlg.pushButton_3.setDisabled(True)
class SecondWindow():
def __init__(self, SW):
self.SW = SW
#Button
SW.pushButton.setText("Calculate")
SW.pushButton.clicked.connect(self.tst) #nothing happens in clicking the button.
SW.show()
def tst(self):
print("testing")
if __name__ == '__main__':
app = QtWidgets.QApplication([])
dlg=uic.loadUi("try.ui")
MainWindow(dlg)
I expect to print the string inside the tst() function from SecondWindow class.
Related
I am trying to make a simple input form that accepts certain inputs and shows output in a table.
As per the code, I get the following output.
But I am looking for the following output.
Following is the code snippet that I have attempted.
import sys
from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui
from PyQt5.QtGui import *
from PyQt5.QtCore import *
# Subclass QMainWindow to customize your application's main window
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("Check Distance Travelled By Vehicles")
self.vehicleNamelbl = QLabel('VehicleName : ')
self.vehicleNamecombo = QComboBox()
self.vehicleNamecombo.addItem('SwitftDzire')
self.dateEdit = QDateEdit()
self.dateEdit.__init__(calendarPopup=True)
self.dateEdit.setDateTime(QtCore.QDateTime.currentDateTime())
self.dateEdit.editingFinished.connect(lambda: date_method())
self.petrolCB = QCheckBox('Petrol')
self.petrolCB.setChecked(True)
self.dieselCB = QCheckBox('Diesel')
self.dieselCB.setChecked(False)
self.petrolCB.stateChanged.connect(self.checkpetrolCB)
self.dieselCB.stateChanged.connect(self.checkdieselCB)
self.submitBtn = QPushButton('Submit ')
# adding action to the date when enter key is pressed
self.submitBtn.clicked[bool].connect(self.collecInput)
grid = QGridLayout()
grid.setSpacing(10)
grid.addWidget(self.vehicleNamelbl,1,0)
grid.addWidget(self.vehicleNamecombo,1,1)
grid.addWidget(self.dateEdit,1,2)
grid.addWidget(self.petrolCB,1,3)
grid.addWidget(self.dieselCB,1,4)
grid.addWidget(self.submitBtn,1,5)
# geometry of the main window
qtRectangle = self.frameGeometry()
# center point of screen
centerPoint = QDesktopWidget().availableGeometry().center()
# move rectangle's center point to screen's center point
qtRectangle.moveCenter(centerPoint)
# top left of rectangle becomes top left of window centering it
self.move(qtRectangle.topLeft())
self.setLayout(grid)
self.show()
# method called by date edit
def date_method():
print('Inside date_method')
# getting the date
value = self.dateEdit.date()
print(value)
print(value.toPyDate())
def checkpetrolCB(self,checked):
if checked :
print('Petrol Vehicle Is Selected')
self.OdFlag = 1
else:
print('Petrol Vehicle Is De-Selected')
def checkdieselCB(self,checked):
if checked :
print('Diesel Vehicle Is Selected')
self.OdFlag = 2
else:
print('Diesel Vehicle Is De-Selected')
def collecInput(self) :
print('Submit Button Pressed!! Inputs Selected')
print(self.vehicleNamecombo.currentText())
print(self.dateEdit.date().toPyDate())
if self.petrolCB.isChecked() == True and self.dieselCB.isChecked() == False :
print('Petrol Vehicle Is Selected')
if self.dieselCB.isChecked() == True and self.petrolCB.isChecked() == False :
print('Diesel Vehicle Is Selected')
if self.petrolCB.isChecked() == True and self.dieselCB.isChecked() == True :
print('Both Petrol And Diesel Vehicle Are Selected')
msgBox = QMessageBox()
msgBox.setIcon(QMessageBox.Critical)
msgBox.setText('Select Either Petrol Or Diesel')
msgBox.setWindowTitle("Alert PopUp")
returnValue = msgBox.exec_()
return
# Call A Module To Get The List Of Files Present As per The Input
vehicleFileList = [ 'dist_SwitftDzire_CityA.13OCT2020','dist_SwitftDzire_CityB.13OCT2020','dist_SwitftDzire_CityC.13OCT2020']
print('Back to collecInput')
print(vehicleFileList)
print('Num Of Files Found : '+str(len(vehicleFileList)))
numOfFiles = len(vehicleFileList)
if numOfFiles == 0 : # No Files Have Been Detected
print('No Files Found')
msgBox = QMessageBox()
msgBox.setIcon(QMessageBox.Critical)
msgBox.setText('No Files Found')
msgBox.setWindowTitle("Alert PopUp")
returnValue = msgBox.exec_()
else: # Atleast 1 File Is Detected
print('Populating table entries')
table = MyTable(vehicleFileList, numOfFiles, 2, self)
# add Qt.Window to table's flags
table.setWindowFlags(table.windowFlags() | Qt.Window)
table.show()
class MyTable(QTableWidget):
def __init__(self, vehicleFileList, *args):
QTableWidget.__init__(self, *args)
self.data = vehicleFileList
self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.resizeColumnsToContents()
self.resizeRowsToContents()
self.horizontalHeader().setStretchLastSection(False)
self.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.setHorizontalHeaderLabels(['Available Vehicle Data Files','Missing Files'])
print('Inside MyTable')
print(vehicleFileList)
rowCount=0
for item in vehicleFileList :
print(item)
self.setItem(rowCount,0,QTableWidgetItem(item))
rowCount+=1
def main():
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
What changes do I need to make to get the window positioning of my choice?
Note: The second window is not a child of the first window.
The idea is to calculate the geometry of the first window and use that information to modify the geometry of the second window:
table = MyTable(vehicleFileList, numOfFiles, 2, self)
# add Qt.Window to table's flags
table.setWindowFlags(table.windowFlags() | Qt.Window)
table.resize(self.width(), table.sizeHint().height())
table.window().move(self.geometry().bottomLeft())
table.show()
I am trying to get a better understanding of how wxPython 'scans'.
Please see my code below:
import os
import wx
from time import sleep
NoFilesToCombine = 0
class PDFFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, -1, title, size=(400,400))
panel = wx.Panel(self)
self.Show()
try: #Set values of PDFNoConfirmed to zero on 1st initialisation
if PDFNoConfimed != 0:
None
except UnboundLocalError:
PDFNoConfimed = 0
try: #Set values of PDFNoConfirmed to zero on 1st initialisation
if PDFNoConfirmedInitially != 0:
None
except UnboundLocalError:
PDFNoConfirmedInitially = 0
while ((PDFNoConfimed == 0) and (PDFNoConfirmedInitially == 0)):
while PDFNoConfirmedInitially == 0:
BoxInputNo = wx.NumberEntryDialog(panel, "So You Want To Combine PDF Files?", "How Many?", "Please Enter", 0, 2, 20)
if BoxInputNo.ShowModal() == wx.ID_OK: #NumberEntryDialog Pressed OK
NoFilesToCombine = BoxInputNo.GetValue()
PDFNoConfirmedInitially = 1
elif BoxInputNo.ShowModal() == wx.ID_CANCEL:
exit()
print(NoFilesToCombine)
ConfirmationLabel = wx.StaticText(panel, -1, label="You Have Selected " + str(NoFilesToCombine) + " Files To Combine, Is This Right?", pos=(20, 100))
ConfirmationBoxConfirm = wx.ToggleButton(panel, label="Confirm", pos=(20, 200))
ConfirmationBoxCancel = wx.ToggleButton(panel, label="Cancel", pos=(180, 200))
#if ConfirmationBoxConfirm.GetValue() == 1:
# exit()
if ConfirmationBoxCancel.GetValue() == 1:
PDFNoConfirmedInitially = 0
app = wx.App()
frame = PDFFrame(None, title="Robs PDF Combiner Application")
app.MainLoop()
Now this is a work in progress so it obviously isn't complete. However what I'm trying to accomplish with the above is:
Display a number entry popup. If user presses 'cancel' exit the application (this works but needs 2 presses for some reason?). If press OK, then:
Display the number entered in step 1, with 2 additional buttons. The 'confirm' doesn't do anything as yet, but the 'cancel' should take you back to step 1. (by resetting the PDFNoConfirmedInitially flag).
Now step 2 doesn't work. When I debug it almost appears as though the PDFFrameonly gets scanned once. My presumably false assumption being that this would be continually scanned due to app.MainLoop() continually scanning wx.App() which in turn would call the child frame?
Help/ pointers/ deeper understanding always appreciated,
Thanks
Rob
1) ShowModal() shows dialog window and you use it two times
if BoxInputNo.ShowModal() == wx.ID_OK:
and
elif BoxInputNo.ShowModal() == wx.ID_CANCEL:
so it shows your window two times.
And only at second time you check wx.ID_CANCEL.
You should run it only once and check its result
result = BoxInputNo.ShowModal()
if result == wx.ID_OK:
pass
elif result == wx.ID_CANCEL:
self.Close()
return
2) You have to assign function to button and this function should reset variable and show dialog window again. But I think wx.Button could be better then wx.ToggleButton
ConfirmationBoxCancel = wx.Button(panel, label="Cancel", pos=(180, 200))
ConfirmationBoxCancel.Bind(wx.EVT_BUTTON, self.on_button_cancel)
def on_button_cancel(self, event):
#print('event:', event)
pass
# reset variable and show dialog window
Frankly I don't understand some of your variables. Maybe if you use True/False instead of 0/1 then they will be more readable. But main problem for me are while loops. GUI frameworks (wxPython, tkinter, PyQt, etc) should run only one loop - Mainloop(). Any other loop may block Mainloop() and GUI will freeze.
I created own version without any while loop but I don't know if it resolve all problems
import wx
class PDFFrame(wx.Frame):
def __init__(self, parent, title):
super().__init__(parent, -1, title, size=(400,400))
self.panel = wx.Panel(self)
self.Show()
# show dialog at start
if self.show_dialog(self.panel):
# create StaticLabel and buttons
self.show_confirmation(self.panel)
else:
# close main window and program
self.Close()
def show_dialog(self, panel):
"""show dialog window"""
global no_files_to_combine
box_input_no = wx.NumberEntryDialog(panel, "So You Want To Combine PDF Files?", "How Many?", "Please Enter", 0, 2, 20)
result = box_input_no.ShowModal()
if result == wx.ID_OK: #NumberEntryDialog Pressed OK
no_files_to_combine = box_input_no.GetValue()
return True
elif result == wx.ID_CANCEL:
print('exit')
return False
def show_confirmation(self, panel):
"""create StaticLabel and buttons"""
self.confirmation_label = wx.StaticText(self.panel, -1, label="You Have Selected {} Files To Combine, Is This Right?".format(no_files_to_combine), pos=(20, 100))
self.confirmation_box_confirm = wx.Button(self.panel, label="Confirm", pos=(20, 200))
self.confirmation_box_cancel = wx.Button(self.panel, label="Cancel", pos=(180, 200))
# assign function
self.confirmation_box_confirm.Bind(wx.EVT_BUTTON, self.on_button_confirm)
self.confirmation_box_cancel.Bind(wx.EVT_BUTTON, self.on_button_cancel)
def update_confirmation(self):
"""update existing StaticLabel"""
self.confirmation_label.SetLabel("You Have Selected {} Files To Combine, Is This Right?".format(no_files_to_combine))
def on_button_cancel(self, event):
"""run when pressed `Cancel` button"""
#print('event:', event)
# without `GetValue()`
if self.show_dialog(self.panel):
# update existing StaticLabel
self.update_confirmation()
else:
# close main window and program
self.Close()
def on_button_confirm(self, event):
"""run when pressed `Confirn` button"""
#print('event:', event)
# close main window and program
self.Close()
# --- main ---
no_files_to_combine = 0
app = wx.App()
frame = PDFFrame(None, title="Robs PDF Combiner Application")
app.MainLoop()
Importing libraries.
from PySide2 import QtWidgets,QtCore,QtGui
from UI import main
This is my class which is inheriting and have a constructor
class MyQtApp(main.Ui_MainWindow,QtWidgets.QMainWindow):
def __init__(self):
super(MyQtApp,self).__init__()
self.setupUi(self)
window size
self.showNormal()
self.submit_pb.clicked.connect(self.fill_box)
self.Menu()
This fill_box is for the combo box, and I have three combo boxes
model_cb, size_cb and color_cb
And the zeroth index is just an empty string for all of them
def fill_box(self):
model = self.model_cb.currentText()
color = self.model_cb.currentText()
size = self.size_cb.currentText()
none = ""
check = True
if model is none:
QtWidgets.QMessageBox.about(self,"Name Required","Please enter the Name!")
check = False
return
if color is none:
QtWidgets.QMessageBox.about(self,"Color Required","Please enter the Color!")
check = False
return
if size is none:
QtWidgets.QMessageBox.about(self,"Size Required","Please Enter the Size!")
check = False
return
if check:
QtWidgets.QMessageBox.about(self, "Done","Submitted")
This Menu function is for the menu bar options what happens if someone click close. I have only two options here 1)close which works fine and 2) Refresh which does not work.
def Menu(self):
self.actionClose.triggered.connect(self.close)
self.actionRefresh.triggered.connect(self.fill_box1)
def fill_box1(self):
#If I do this It will reset all the boxes to its original empty
#strings but then I would not have all the methods in the class
#to add the functionality.
self.setupUi(self)
if __name__ == '__main__':
app = QtWidgets.QApplication()
qt_app = MyQtApp()
qt_app.show()
app.exec_()
I am designing a program to edit DICOMs. Specifically, I am having issues appropriately interacting with my PyQt UI.
I want to be able to click on a "pause" and on a "stop" button to either pause or stop my editing function. My editing function takes a significant amount of time to process / loop through. Depending on the number of files that it is editing, it can take anywhere from 30 seconds to over an hour. Because of this, I decided to throw my editing function into its own thread using the native threading capabilities of Qt. I was able to get the thread working ie: from my MainWindow class I can click a button that initializes my editing class (class edit(QThread), however interacting with the GUI still crashes the program and I'm not sure why! Below I have added a sample of the general code structure / set up that I am using.
class anonymizeThread(QThread):
def __init__(self):
QThread.__init__(self)
def __del__(self):
self.wait()
#def sendAnon(self, progress_val):
# self.completed = 0
# return self.completed
def run(self):
# while self.completed < 100:
# self.completed += 0.00001
# self.emit(QtCore.SIGNAL('PROGRESS'), self.completed)
# ANONYMIZE FUNCTION!
i = 0
#flag = self.stop_flag
while i < 10000000: # and self.stop_flag is not 1:
print(i)
i+=1
print('i didnt enter the loop')
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
# connect the buttons
self.worker = anonymizeThread()
self.anonbtn.clicked.connect(self.anonymize)
self.open_directory.clicked.connect(self.open_dir)
self.pause.clicked.connect(self.paused)
self.stopbtn.clicked.connect(self.stopped)
# block button signals to start
self.pause.blockSignals(True)
self.stopbtn.blockSignals(True)
self.dir_name = None
self.pause_flag = None
self.stop_flag = None
self.anon_flag = None
# This is how we quit from the main menu "File" option
extractAction = self.actionQuit_Ctrl_Q
extractAction.setShortcut("Ctrl+Q")
extractAction.setStatusTip('Leave The App')
extractAction.triggered.connect(self.close_application)
def updateProgressBar(self,val):
self.progressBar.setValue(val)
def close_application(self):
choice = QMessageBox.question(self, 'Just had to check...', "Are you sure you want to exit?", QMessageBox.Yes | QMessageBox.No)
if choice == QMessageBox.Yes:
sys.exit()
else:
pass
def anonymize(self):
self.pause.blockSignals(False)
self.stopbtn.blockSignals(False)
self.worker.start()
# check if directory chosen
# self.progressBar.setMaximum(len(dcm)
# start our anon thread!
def paused(self):
#only if running
if self.pause_flag is 0:
self.pause_flag = 1
self.pause.setText('Start')
elif self.pause_flag is 1:
self.pause_flag = 0
self.pause.setText('Pause')
else:
pass
def stopped(self): # need a self.stop() for anonThread
choice = QMessageBox.question(self,'Stop', "Are you sure you want to stop? You will not be able to pick up exactly where you left off.",
QMessageBox.Yes | QMessageBox.No)
if choice == QMessageBox.Yes:
self.stop_flag = 1
#self.stopbtn.blockSignals(True)
#self.paused.blockSignals(True)
else:
pass
def open_dir(self):
self.dir_name = str(QFileDialog.getExistingDirectory(self, "Select Directory"))
if len(self.dir_name) is not 0:
self.anon_flag = 0
def main():
app = QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
It is advisable not to access the flags directly, it is better to do it through the functions to make use of it transparently, for this the same class should verify the tasks.
Also it is good to give a small delay so that the application can deal with the graphic part, another possible improvement is to avoid usat sys.exit, you could call the close method that closes the window.
In the following code I have implemented the stop and pause methods.
class anonymizeThread(QThread):
def __init__(self):
QThread.__init__(self)
self.onRunning = True
self.onStop = False
def __del__(self):
self.wait()
def stop(self):
self.onStop = True
def pause(self):
if self.isRunning():
self.onRunning = not self.onRunning
def run(self):
i = 0
#flag = self.stop_flag
while i < 10000000:
if self.onRunning: # and self.stop_flag is not 1:
print(i)
i+=1
if self.onStop:
break
QThread.msleep(10)
print('i didnt enter the loop')
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
# connect the buttons
self.worker = anonymizeThread()
self.anonbtn.clicked.connect(self.anonymize)
self.pause.clicked.connect(self.paused)
self.stopbtn.clicked.connect(self.stopped)
# block button signals to start
self.pause.blockSignals(True)
self.stopbtn.blockSignals(True)
def close_application(self):
choice = QMessageBox.question(self, 'Just had to check...', "Are you sure you want to exit?", QMessageBox.Yes | QMessageBox.No)
if choice == QMessageBox.Yes:
self.close()
def anonymize(self):
self.pause.blockSignals(False)
self.stopbtn.blockSignals(False)
self.worker.start()
def paused(self):
self.worker.pause()
def stopped(self): # need a self.stop() for anonThread
choice = QMessageBox.question(self,'Stop', "Are you sure you want to stop? You will not be able to pick up exactly where you left off.",
QMessageBox.Yes | QMessageBox.No)
if choice == QMessageBox.Yes:
self.worker.stop()
Thanks to #eyllansec and #ekhumoro..
In the above code, all instances of self.stop_flag = ... should have been self.worker.stop_flag = ... as it is changing the variable that is to be used in the worker class/thread. My mistake was assuming both classes inherited the same "self".
If there are other errors and or better explanations of what I did incorrectly, please do post an answer and I'll accept it!
I have created a window with QTableWidget having a cell with 2 buttons.
Buttons are created in seperate class where i am passing QTableWidget instance from main procedure.
I am not able to get the button events, which are connected in button Creation class. My code snippet is as below
class Buttons():
def __init__(self,tab):
buttonLayout = QtGui.QHBoxLayout()
buttonLayout.setContentsMargins(0,0,0,0)
self.saveButtonItem = QtGui.QPushButton('Save')
self.deleteButtonItem = QtGui.QPushButton('Delete')
buttonLayout.addWidget(self.saveButtonItem)
buttonLayout.addWidget(self.deleteButtonItem)
cellWidget = QtGui.QWidget()
cellWidget.setLayout(buttonLayout)
tab.insertRow(tab.rowCount())
tab.setCellWidget(tab.rowCount() - 1,0,cellWidget)
self.setconncection()
def setconncection(self):
self.saveButtonItem.clicked.connect(self.btnSaveClicked)
self.deleteButtonItem.clicked.connect(self.btnDeleteClicked)
print 'connections are set'
def btnSaveClicked(self):
print 'save clicked'
def btnDeleteClicked(self):
print 'delete clicked'
class testing(QtGui.QTableWidget):
def __init__(self):
super(testing,self).__init__()
self.setColumnCount(1)
for i in xrange(3):
self.r = Buttons(self)
if __name__ == "__main__" :
import sys
app = QtGui.QApplication (sys.argv)
win = testing ()
win.show()
sys.exit(app.exec_())
My window at run time is as below
After the __init__ of testing, the reference to Buttons instance is lost and the object is destroyed. (Variable r is affected but not used.)
Keeping a link to it (see last line in following code snippet) makes it work.
class testing(QtGui.QTableWidget):
def __init__(self):
super(testing,self).__init__()
self.setColumnCount(1)
self.setRowCount(1)
self.buttons = []
for i in xrange(3):
self.buttons.append(Buttons(self))