Can the style of a custom QFileDialog be changed - python-3.x

I did a custom QFileDialog in other to add a label and a check box to it. It works the way I want but the problem is that when you modify this class the style changes since we aren't calling the static method. I'm doing this in a larger project and this change in style isn't aesthetically pleasing to the user, compared to how the whole app looks. Is there a way to style it? I'm sure the style changes due to this options=QtWidgets.QFileDialog.DontUseNativeDialog, but if I take it out, the code won't work. Below is a sample of the code
import sys
from PyQt5 import QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
button = QtWidgets.QPushButton("Open")
button.clicked.connect(self.OpenFile)
button.setStyleSheet('background-color: rgba(53, 53, 53,50)')
save_button = QtWidgets.QPushButton("Save")
# save_button.clicked.connect(self.savingFile)
save_button.setStyleSheet('background-color: rgba(53, 53, 53,50)')
hlayout = QtWidgets.QHBoxLayout()
hlayout.addWidget(button)
hlayout.addWidget(save_button)
lay = QtWidgets.QVBoxLayout(self)
lay.addLayout(hlayout)
def OpenFile(self):
dialog = QtWidgets.QFileDialog(
self,
"Open File",
"",
"Image Files (*.dcm *.DCM *.tif *.tiff *.TIF "
"*.TIFF *.oct *.OCT);;All Files (*)",
supportedSchemes=["file"],
options=QtWidgets.QFileDialog.DontUseNativeDialog,
)
checkBox = QtWidgets.QCheckBox()
labelWidget = QtWidgets.QLabel()
labelWidget.setText("Repeated Frame Averaging")
dialog.layout().addWidget(labelWidget)
dialog.layout().addWidget(checkBox)
dialog.setOption(QtWidgets.QFileDialog.DontUseNativeDialog, True)
if dialog.exec_() == QtWidgets.QDialog.Accepted:
filename = dialog.selectedFiles()[0]
cbSelection = checkBox.isChecked()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())

Related

Reverting imported dictionary via QPushButton issues

I am having trouble understanding why a deep copy of a dictionary reverts back to original values when I run the revert() method once, but when I change values again, and run the revert() method again it changes the copied dictionaries values along with the original.
The dictionary/values are being imported from another file. I can only assume it is because the Test is being imported more than once.
Can someone help explain why this is happening and what can I do to avoid it?
Test.py
import ujson,copy
nested1 = {'1':None, '2':"String"}
nested2 = {'1':0.5123, '2':515}
diction = {'1':nested1, '2':nested2}
copyDiction = ujson.loads(ujson.dumps(diction))
copyOtherDiction = copy.deepcopy(diction)
Main.py
import Test
from PyQt5 import QtCore, QtWidgets, QtGui
class Window(QtWidgets.QMainWindow):
def __init__(self, parent = None):
super(Window,self).__init__(parent)
widget = QtWidgets.QWidget()
self.setCentralWidget(widget)
layout = QtWidgets.QVBoxLayout()
self.lineEdit = QtWidgets.QLineEdit()
self.button = QtWidgets.QPushButton("Change Value")
self.button.clicked.connect(self.changeMethod)
self.revertbutton = QtWidgets.QPushButton("Revert")
self.revertbutton.clicked.connect(self.revert)
layout.addWidget(self.lineEdit)
layout.addWidget(self.button)
layout.addWidget(self.revertbutton)
widget.setLayout(layout)
def changeMethod(self):
text = self.lineEdit.text()
if text.isdigit():
Test.diction['1']['2'] = int(text)
else:
Test.diction['1']['2'] = text
def revert(self):
print(Test.diction)
Test.diction = Test.copyDiction
print(Test.diction)
print(Test.copyDiction)
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

Sending a signal from a button to a parent window

I'm making an app with PyQt5 that uses a FileDialog to get files from the user and saves the file names in a list. However I also want to be able to remove those entries after they are added, so I created a class that has a name(the file name) and a button. The idea is that when this button is clicked the widget disappears and the file entry is removed from the list. The disappearing part works fine but how to I get the widget to remove the entry form the list? How can i send a signal from one widget inside the window to the main app and tell it to remove the entry from the list?
I know the code is very bad, I'm still very new to PyQt and Python in general so any advice would be greatly appreciated.
from PyQt5 import QtWidgets as qw
import sys
class MainWindow(qw.QMainWindow):
def __init__(self):
super().__init__()
# List of opened files
self.files = []
# Main Window layout
self.layout = qw.QVBoxLayout()
self.file_display = qw.QStackedWidget()
self.file_button = qw.QPushButton('Add File')
self.file_button.clicked.connect(self.add_file)
self.layout.addWidget(self.file_display)
self.layout.addWidget(self.file_button)
self.setCentralWidget(qw.QWidget())
self.centralWidget().setLayout(self.layout)
# Open File Dialog and append file name to list
def add_file(self):
file_dialog = qw.QFileDialog()
self.files.append(file_dialog.getOpenFileName())
self.update_stack()
# Create new widget for StackedWidget remove the old one and display the new
def update_stack(self):
new_stack_item = qw.QWidget()
layout = qw.QVBoxLayout()
for file in self.files:
layout.addWidget(FileWidget(file[0]))
new_stack_item.setLayout(layout)
if len(self.file_display) > 0:
temp_widget = self.file_display.currentWidget()
self.file_display.removeWidget(temp_widget)
self.file_display.addWidget(new_stack_item)
class FileWidget(qw.QWidget):
def __init__(self, name):
# This widget is what is added when a new file is opened
# it has a file name and a close button
# my idea is that when the close button is pressed the widget is removed
# from the window and from the files[] list in the main class
super().__init__()
self.layout = qw.QHBoxLayout()
self.file_name = qw.QLabel(name)
self.close_button = qw.QPushButton()
self.close_button.clicked.connect(self.remove)
self.layout.addWidget(self.file_name)
self.layout.addWidget(self.close_button)
self.setLayout(self.layout)
def remove(self):
self.close()
if __name__ == '__main__':
app = qw.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
You need to remove from the list in the remove method of theFileWidget class.
import sys
from PyQt5 import QtWidgets as qw
class FileWidget(qw.QWidget):
def __init__(self, name, files): # + files
super().__init__()
self.files = files # +
self.name = name # +
self.layout = qw.QHBoxLayout()
self.file_name = qw.QLabel(name)
self.close_button = qw.QPushButton("close {}".format(name))
self.close_button.clicked.connect(self.remove)
self.layout.addWidget(self.file_name)
self.layout.addWidget(self.close_button)
self.setLayout(self.layout)
def remove(self):
self.files.pop(self.files.index(self.name)) # <<<-----<
self.close()
class MainWindow(qw.QMainWindow):
def __init__(self):
super().__init__()
# List of opened files
self.files = []
# Main Window layout
self.layout = qw.QVBoxLayout()
self.file_display = qw.QStackedWidget()
self.file_button = qw.QPushButton('Add File')
self.file_button.clicked.connect(self.add_file)
self.layout.addWidget(self.file_display)
self.layout.addWidget(self.file_button)
self.setCentralWidget(qw.QWidget())
self.centralWidget().setLayout(self.layout)
# Open File Dialog and append file name to list
def add_file(self):
file_name, _ = qw.QFileDialog().getOpenFileName(self, 'Open File') # +
if file_name: # +
self.files.append(file_name) # +
self.update_stack()
# Create new widget for StackedWidget remove the old one and display the new
def update_stack(self):
new_stack_item = qw.QWidget()
layout = qw.QVBoxLayout()
for file in self.files:
layout.addWidget(FileWidget(file, self.files)) # + self.files
new_stack_item.setLayout(layout)
if len(self.file_display) > 0:
temp_widget = self.file_display.currentWidget()
self.file_display.removeWidget(temp_widget)
self.file_display.addWidget(new_stack_item)
if __name__ == '__main__':
app = qw.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())

Close second widget after pressing save button pyqt5

I am writing an application where main widget windows opens second widget window and in the second widget window, I am taking some inputs from user and on hitting save button, second widget window should saves the data into xml file and should get closed but the second window is not closing.
I tried most of the things from google like self.close(), self.destroy(),self.hide() self.window().hide(), self.window().destroy() none of them are working.
I don't want to do sys.exit() as this is closing complete application but just have to close secondWidgetWindow after clicking save button so that user can do another work in first widget window.
Below is the snippet :
FirstWidgetWindow.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_firstWidgetWindow(QtWidgets.QMainWindow):
def __init__(self,firstWidgetWindow):
super().__init__()
self.setupUi(firstWidgetWindow)
def setupUi(self, firstWidgetWindow):
### code to create Button ###
self.btnOpenNewWidgetWindow.clicked.connect(self.openNewWindow)
def openNewWindow(self):
self.secondWidgetWindow = QtWidgets.QWidget()
self.ui = Ui_secondWidgetWindow()
self.ui.setupUi(self.secondWidgetWindow)
self.secondWidgetWindow.show()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
firstWidgetWindow = QtWidgets.QWidget()
ui = Ui_firstWidgetWindow(firstWidgetWindow)
firstWidgetWindow.show()
sys.exit(app.exec_())
secondWidgetWindow.py
class Ui_secondWidgetWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
def setupUi(self, secondWidgetWindow):
### creating line edit to take input from user
### creating save button
self.btnSave.clicked.connect(self.saveUserInput)
def saveUserInput(self):
## saving user inputs in xml file
self.close() ## here i needs to close this window.
Close second widget after pressing save button:
self.secondWidgetWindow.hide()
Try it:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_secondWidgetWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.secondWidgetWindow = None
def setupUi(self, secondWidgetWindow):
self.secondWidgetWindow = secondWidgetWindow
### creating line edit to take input from user
self.line_edit = QtWidgets.QLineEdit(secondWidgetWindow)
self.line_edit.setGeometry(20, 20, 300, 20)
### creating save button
self.btnSave = QtWidgets.QPushButton('save', secondWidgetWindow)
self.btnSave.setGeometry(50, 50, 100, 50)
self.btnSave.clicked.connect(self.saveUserInput)
def saveUserInput(self):
## saving user inputs in xml file
#self.close() ## here i needs to close this window.
self.secondWidgetWindow.hide()
QtWidgets.QMessageBox.information(self, "SAVE",
"saving user inputs in xml file")
class Ui_firstWidgetWindow(QtWidgets.QMainWindow):
def __init__(self,firstWidgetWindow):
super().__init__()
self.setupUi(firstWidgetWindow)
def setupUi(self, firstWidgetWindow):
### code to create Button ###
self.btnOpenNewWidgetWindow = QtWidgets.QPushButton('OpenNewWidgetWindow', firstWidgetWindow)
self.btnOpenNewWidgetWindow.setGeometry(50, 100, 300, 50)
self.btnOpenNewWidgetWindow.clicked.connect(self.openNewWindow)
def openNewWindow(self):
self.secondWidgetWindow = QtWidgets.QWidget()
self.ui = Ui_secondWidgetWindow()
self.ui.setupUi(self.secondWidgetWindow)
self.secondWidgetWindow.show()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
firstWidgetWindow = QtWidgets.QWidget()
ui = Ui_firstWidgetWindow(firstWidgetWindow)
firstWidgetWindow.setGeometry(700, 250, 400, 200)
firstWidgetWindow.show()
sys.exit(app.exec_())

PyQt5 - Can QTabWidget content extend up to Main Window edges, even with no content?

I am new to PyQt5... Simple question here.
I am using PyQt5 to build a simple application. This application has a Main Window containing a QTabWidget with 3 tabs. Once the application starts, all tab pages are empty and get filled later on. When tab pages are empty, I would still like them to appear as blank pages and extend up to the Main Window edges.
I've been trying to achieve this in two ways: using a layout and using the setGeometry function. Yet the tab pages never extend vertically very far, and horizontally they never go beyond the last tab. See code below.
import sys
from PyQt5.QtWidgets import *
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Window With Tabs")
self.setGeometry(50,50,400,400)
oTabWidget = QTabWidget(self)
oPage1 = QWidget()
oLabel1 = QLabel("Hello",self)
oVBox1 = QVBoxLayout()
oVBox1.addWidget(oLabel1)
oPage1.setLayout(oVBox1)
oPage2 = QWidget()
oPage2.setGeometry(0,0,400,400)
oPage3 = QWidget()
oPage3.setGeometry(0,0,400,400)
oTabWidget.addTab(oPage1,"Page1")
oTabWidget.addTab(oPage2,"Page2")
oTabWidget.addTab(oPage3,"Page3")
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
oMainwindow = MainWindow()
sys.exit(app.exec_())
Any idea how to modify the code so the empty pages will extend up to the edges of Main Window ?
Set a layout on the main widget:
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Window With Tabs")
self.setGeometry(50,50,400,400)
layout = QVBoxLayout(self)
oTabWidget = QTabWidget(self)
layout.addWidget(oTabWidget)
The setGeometry calls on the other widgets are redundant.
import sys
from PyQt5.QtWidgets import *
class MainWindow(QWidget):
# window object
def __init__(self):
super().__init__()
self.initGUI() # call custom code
def initGUI(self):
self.setWindowTitle("Window With Tabs") # window...
self.setGeometry(50,50,400,400) #...properties
TabW=self.createTabs() # a custom-tab object
layout = QVBoxLayout(self) # main window layout
layout.addWidget(TabW) #populate layout with Tab object
self.show() # display window
def createTabs(self): # create and return Tab object
oPage1 = QWidget() # tabs...
oPage2 = QWidget()
oPage3 = QWidget()
oTabWidget = QTabWidget() # Tabobject
oTabWidget.addTab(oPage1,"Page1") # populate tab object...
oTabWidget.addTab(oPage2,"Page2")
oTabWidget.addTab(oPage3,"Page3")
return oTabWidget # return tab object
if __name__ == "__main__": # Rest is History!
app = QApplication(sys.argv)
oMainwindow = MainWindow()
sys.exit(app.exec_())

How do I thread a single method on a PyQt GUI so that the rest of the GUI is still accessible?

Basically, when the Switch Button is pressed, which is connected to the reconfigure method, I want everything in the reconfigure method to run as a separate thread/process so the main GUI is still accessible and not being blocked. Below is a watered down version of my code.
import sys, time
from PyQt4 import QtGui, QtCore
from PyQt4.Qt import *
#//Popup Class - Will appear when the Switch Button is pressed
class Popup(QWidget):
def __init__(self):
QWidget.__init__(self)
#//nothing here now, it will have a message telling user to wait while program is run
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
grid = QtGui.QGridLayout()
label_header = QtGui.QLabel("TEST RECONFIGURE")
font = label_header.font()
font.setPointSize(24)
label_header.setFont(font)
#//Creating Static Labels that will be placed in the GUI
label_1 = QtGui.QLabel("Menu 1:")
label_2 = QtGui.QLabel("Menu 2:")
label_spacer = QtGui.QLabel("")
label_cfg = QtGui.QLabel("Current Configuration: '/tmp/directory_here' ")
global comboBox1
comboBox1 = QtGui.QComboBox()
comboBox1.addItem("1")
comboBox1.addItem("2")
global comboBox2
comboBox2 = QtGui.QComboBox()
comboBox2.addItem("3")
comboBox2.addItem("4")
#//Switch Button!!!
global switchButton
switchButton = QPushButton("Switch")
switchButton.clicked.connect(self.reconfigure)
quitButton = QtGui.QPushButton('Quit')
quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit)
#//Configure the grid layout
grid.addWidget(label_spacer, 0,0,9,9)
grid.addWidget(label_header, 0,0,1,6)
grid.addWidget(label_1, 1,0,1,1)
grid.addWidget(comboBox1, 2,0,1,1)
grid.addWidget(label_2, 3,0,1,1)
grid.addWidget(comboBox2, 4,0,1,1)
grid.addWidget(switchButton, 5,0,1,2)
grid.addWidget(label_cfg, 6,0,1,9)
grid.addWidget(quitButton, 9,9,1,1)
self.setLayout(grid)
self.setGeometry(640,300,400,600)
self.show()
#//open up the popup window for switch button, and reconfigure
def reconfigure(self):
print "Opening New Window"
self.w = Popup()
self.w.setGeometry(QRect(self.x()+100,self.y()+100,400,200))
self.w.show()
txt1 = str(comboBox1.currentText())
txt2 = str(comboBox2.currentText())
print " reconfiguring to option %s and option %s" %(txt1, txt2)
#
# This is where most of the work is done, and takes about 1/2 an hour for everything to run
# Want to make this method a separate thread/process so the rest of the main GUI is still accessible
# while the program is running as the whole class will be a separate tab in a larger GUI
#
print "all done!"
#//runner
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I feel like I have to use threading and signals to accomplish this, but I am not having much luck. Any help would be greatly appreciated. Thank you!
import sys, time
from PyQt4 import QtGui, QtCore
from PyQt4.Qt import *
class ConfigureThread(QtCore.QThread):
def run(self):
pass
#
# This is where most of the work is done, and takes about 1/2 an hour for everything to run
# Want to make this method a separate thread/process so the rest of the main GUI is still accessible
# while the program is running as the whole class will be a separate tab in a larger GUI
#
#//Popup Class - Will appear when the Switch Button is pressed
class Popup(QWidget):
def __init__(self):
QWidget.__init__(self)
#//nothing here now, it will have a message telling user to wait while program is run
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
grid = QtGui.QGridLayout()
label_header = QtGui.QLabel("TEST RECONFIGURE")
font = label_header.font()
font.setPointSize(24)
label_header.setFont(font)
#//Creating Static Labels that will be placed in the GUI
label_1 = QtGui.QLabel("Menu 1:")
label_2 = QtGui.QLabel("Menu 2:")
label_spacer = QtGui.QLabel("")
label_cfg = QtGui.QLabel("Current Configuration: '/tmp/directory_here' ")
global comboBox1
comboBox1 = QtGui.QComboBox()
comboBox1.addItem("1")
comboBox1.addItem("2")
global comboBox2
comboBox2 = QtGui.QComboBox()
comboBox2.addItem("3")
comboBox2.addItem("4")
#//Switch Button!!!
global switchButton
switchButton = QPushButton("Switch")
switchButton.clicked.connect(self.reconfigure)
quitButton = QtGui.QPushButton('Quit')
quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit)
#//Configure the grid layout
grid.addWidget(label_spacer, 0,0,9,9)
grid.addWidget(label_header, 0,0,1,6)
grid.addWidget(label_1, 1,0,1,1)
grid.addWidget(comboBox1, 2,0,1,1)
grid.addWidget(label_2, 3,0,1,1)
grid.addWidget(comboBox2, 4,0,1,1)
grid.addWidget(switchButton, 5,0,1,2)
grid.addWidget(label_cfg, 6,0,1,9)
grid.addWidget(quitButton, 9,9,1,1)
self.setLayout(grid)
self.setGeometry(640,300,400,600)
self.show()
#//open up the popup window for switch button, and reconfigure
def reconfigure(self):
print("Opening New Window")
self.w = Popup()
self.w.setGeometry(QRect(self.x()+100,self.y()+100,400,200))
self.w.show()
txt1 = str(comboBox1.currentText())
txt2 = str(comboBox2.currentText())
print(" reconfiguring to option %s and option %s" %(txt1, txt2))
self.th = ConfigureThread()
self.th.finished.connect(self.configuring_done)
self.th.start()
def configuring_done(self):
print("all done!")
#//runner
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

Resources