Retrieve data from a dialog in the calling window - python

I am struggling to retrieve results from a QDialog window and pass them back to the previous window. I want the user to be able to select a value/values, and then once they click okay in the dialog window, it should return them back to the previous window, and pass the text into the byVariables Textbox. The error returns on the line self.procUnivariate.byVariables.setText(item.text()). The error states:
AttributeError: 'ProcUnivariateVariables' object has no attribute 'procUnivariate'
I also tried using a return statement as you can see that is commented out. Unfortunately it seemed like the code got stuck and wasn't moving to the next line as I threw a print statement after and it never printed that line. I need help figuring out how to pass it back to the ProcUnivariate class once the okay button is clicked. Also, if I can figure this out, I'll likely turn the ProcUnivariate Class into a dialog window as well because it should take away the focus from the main window and shouldn't stay open if the main window is closed.
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QListWidget, QLineEdit, QTextEdit, QGridLayout, QHBoxLayout, QVBoxLayout, QDialog, QSizePolicy, QFileDialog, QTabWidget, QCheckBox
import PyQt5.QtGui as qtg
import glob
import os
from PyQt5.QtCore import Qt, QSettings
import inspect
from PyQt5 import QtCore
import pandas as pd
import pathlib
import pyreadstat
import json
class ProcUnivariateVariables(QDialog):
def __init__(self):
super().__init__()
self.procUnivariateByVariables = []
self.layout = QGridLayout()
self.setLayout(self.layout)
self.allVariables = QListWidget()
self.allVariables.setSelectionMode(3)
self.variablesSelected = QListWidget()
self.variablesSelected.setSelectionMode(3)
self.layout.addWidget(self.allVariables, 1,0, 4, 1)
self.layout.addWidget(self.variablesSelected, 1, 1, 4, 1)
self.okButton = QPushButton("Ok")
self.resetButton = QPushButton("Reset")
self.cancelButton = QPushButton("Cancel")
self.layout.addWidget(self.okButton, 1, 2)
self.layout.addWidget(self.resetButton, 2, 2)
self.layout.addWidget(self.cancelButton, 3, 2)
self.addByVariable = QPushButton(">")
self.removeVariable = QPushButton("<")
self.layout.addWidget(self.addByVariable, 5, 0)
self.layout.addWidget(self.removeVariable, 5, 1)
self.button_Connections()
def setItems(self, items):
self.allVariables.clear()
for item in items:
self.allVariables.addItem(item)
def add_by_variable(self):
selected_elements=[item.text() for item in self.allVariables.selectedItems()]
variableItem = self.variablesSelected.insertItems(self.variablesSelected.count(),selected_elements)
def button_Connections(self):
self.addByVariable.clicked.connect(self.add_by_variable)
self.removeVariable.clicked.connect(self.remove_variable)
self.okButton.clicked.connect(self.okay_clicked)
def remove_variable(self):
removeVariables = [item.text() for item in self.variablesSelected.selectedItems()]
self.selectedVariables.takeItems(removeVariables)
#sourceItem = self.currentSource.takeItem(oldSource)
def okay_clicked(self):
self.byVariablesSelected = [item.text() for item in self.variablesSelected.selectedItems()]
#self.procUnivariateByVariables = byVariablesSelected
print(self.byVariablesSelected)
self.accept()
#return self.byVariablesSelected
for item in self.byVariablesSelected:
print(item)
self.procUnivariate.byVariables.setText(item.text())
class ProcUnivariate(QWidget):
def __init__(self):
super().__init__()
self.procUnivariateVariables = None
layout = QGridLayout(self)
##Proc Univariate window Widgets
self.by = QLabel("By")
self.byVariables = QLineEdit()
self.byVariableList = QListWidget()
self.byButton = QPushButton("...")
self.varLabel = QLabel("Var")
self.classLabel = QLabel("Class")
self.freqLabel = QLabel("Freq")
self.histogramLabel = QLabel("Histogram")
self.freqBox = QLineEdit()
self.histBox = QLineEdit()
self.varBox = QLineEdit()
self.varButton = QPushButton("...")
self.sourceLabel = QLabel("Name")
self.sourceText = QLineEdit()
self.sourceButton = QPushButton("...")
self.selectionLabel = QLabel("Selection criteria")
self.selectionCriteria = QTextEdit()
self.statisticLabel = QLabel("Output")
self.statisticSearch = QLineEdit()
self.statisticList = QListWidget()
self.statisticList.setSortingEnabled(True)
self.outputLabel = QLabel("Output Statement")
self.outputText = QTextEdit()
self.fileOutputPath = QLineEdit("Output File Path")
self.runButton = QPushButton("Run")
self.previewButton = QPushButton("Preview")
self.okButton = QPushButton("Ok")
self.resetButton = QPushButton("Reset")
self.cancelButton = QPushButton("Cancel")
self.secondWindowConnections()
layout.addWidget(self.by, 1,0,1,1)
layout.addWidget(self.byVariables, 2, 0, 1, 4)
layout.addWidget(self.byButton, 2, 5, 1, 1)
#layout.addWidget(self.byVariableList, 3, 0, 1, 1)
layout.addWidget(self.freqLabel, 3, 0)
layout.addWidget(self.freqBox, 4, 0, 1, 4)
layout.addWidget(self.histogramLabel, 5, 0)
layout.addWidget(self.histBox, 6, 0, 1, 4)
layout.addWidget(self.varLabel, 7, 0, 1, 4)
layout.addWidget(self.varBox, 8, 0)
layout.addWidget(self.varButton, 8,5)
layout.addWidget(self.sourceLabel, 1, 6)
layout.addWidget(self.sourceText, 2, 6, 1, 4)
layout.addWidget(self.sourceButton, 2, 10)
layout.addWidget(self.selectionLabel, 3, 6)
layout.addWidget(self.selectionCriteria, 4, 6, 1, 4)
layout.addWidget(self.statisticLabel, 5, 6)
layout.addWidget(self.statisticSearch, 6, 6, 1, 4)
layout.addWidget(self.statisticList, 7, 6, 3, 4)
layout.addWidget(self.outputLabel, 10, 6)
layout.addWidget(self.outputText, 11, 6, 1, 4)
layout.addWidget(self.runButton, 12, 6)
layout.addWidget(self.previewButton, 12, 7)
layout.addWidget(self.okButton, 12, 8)
layout.addWidget(self.resetButton, 12, 9)
layout.addWidget(self.cancelButton, 12, 10)
self.setLayout(layout)
def secondWindowConnections(self): # this had a typo
self.byButton.clicked.connect(self.show_third_window)
def show_third_window(self):
if self.procUnivariateVariables is None: # if window has been created yet
self.procUnivariateVariables = ProcUnivariateVariables() # create window
if not self.procUnivariateVariables.isVisible(): # if window is showing
self.procUnivariateVariables.show() # show window
self.procUnivariateVariables.setItems(self.procUnivariateVariablesItems) # send items to window
def send_items(self, items): # this is to collect the variable that
self.procUnivariateVariablesItems = items # move to the third window
class MainWindow(QWidget):
def __init__(self):
super().__init__()
# Add a title
self.setWindowTitle("GUI Querying Program")
self.layout = QHBoxLayout()
self.setLayout(self.layout)
self.initUI()
self.setButtonConnections()
self.sw = None # dont initialize until neccessary.
def initUI(self):
subLayouts = {}
subLayouts['LeftColumn'] = QGridLayout()
self.layout.addLayout(subLayouts['LeftColumn'],1)
self.buttons = {}
self.buttons['addVariable'] = QPushButton('>')
self.buttons['removeVariable'] = QPushButton('<')
self.buttons['Toolkit'] = QPushButton('Toolkit')
self.variables = QListWidget()
self.selectedVariables = QListWidget()
subLayouts['LeftColumn'].addWidget(self.variables, 7,0,4,1)
subLayouts['LeftColumn'].addWidget(self.selectedVariables, 7,1,4,1)
subLayouts['LeftColumn'].addWidget(self.buttons['addVariable'], 10,0,1,1)
subLayouts['LeftColumn'].addWidget(self.buttons['removeVariable'], 10,1,1,1)
subLayouts['LeftColumn'].addWidget(self.buttons['Toolkit'], 11,1,1,1)
names = ['apple', 'banana', 'Cherry']
self.variables.insertItems(0, names)
def setButtonConnections(self):
self.buttons['addVariable'].clicked.connect(self.add_variable)
self.buttons['Toolkit'].clicked.connect(self.show_new_window)
# self.buttons['Toolkit'].clicked.connect(self.add_selected_variables)
# only use one connnect slot
def add_variable(self):
for item in self.variables.selectedItems():
self.selectedVariables.addItem(item.clone())
def show_new_window(self):
if self.sw is None: # check if window has been constructed
self.sw = ProcUnivariate() # construct window
if not self.sw.isVisible(): # If winow is not showing
self.sw.show() # show window
self.sw.send_items(self.add_selected_variables()) # send selected
# variables to second window
def add_selected_variables(self):
items = []
for i in range(self.selectedVariables.count()):
items.append(self.selectedVariables.item(i).clone())
# self.tw.setItems(items) ... self.tw doesnt exist so return them
return items
if __name__ == "__main__":
import sys
app = QApplication([])
mw = MainWindow()
mw.show()
app.exec()

What you need to do is connect a slot to the accepted signal of the dialog, and then retrieve the variables via a dedicated method of the dialog when that signal is emitted.
Here are all the relevant changes (fully tested as working):
class ProcUnivariateVariables(QDialog):
...
def button_Connections(self):
...
# connect to the dialog's built-in accept slot
self.okButton.clicked.connect(self.accept)
# add a method for retrieving the variables
def byVariablesSelected(self):
return [item.text() for item in self.variablesSelected.selectedItems()]
class ProcUnivariate(QWidget):
...
def secondWindowConnections(self): # this had a typo
self.byButton.clicked.connect(self.show_third_window)
self.varButton.clicked.connect(self.show_third_window)
def show_third_window(self):
if self.procUnivariateVariables is None: # if window has been created yet
self.procUnivariateVariables = ProcUnivariateVariables() # create window
# connect the new slot to the dialog's built-in accepted signal
self.procUnivariateVariables.accepted.connect(self.receive_selected_variables)
if not self.procUnivariateVariables.isVisible(): # if window is showing
self.procUnivariateVariables.show() # show window
self.procUnivariateVariables.setItems(self.procUnivariateVariablesItems) # send items to window
# set an identifier from the source button
self.procUnivariateVariables.sourceName = self.sender().text()
# add a slot for handling the dialog's accepted signal
def receive_selected_variables(self):
variables = self.procUnivariateVariables.byVariablesSelected()
text = ', '.join(variables)
if self.procUnivariateVariables.sourceName == 'byButton':
self.byVariables.setText(text)
else:
self.varBox.setText(text)
(Note that the above changes make the okay_clicked method of ProcUnivariateVariables redundant, so it should be removed).

Related

Python PyQt5 MVC framework use of lambdas not working

Good Evening,
I am working on one of my first Python programs utilizing the MVC framework. I have looked at several tutorials and examples of MVC and I followed a youTube series of creating a calulator using MVC from Life in Code. https://www.youtube.com/channel/UCb__or4F5GkZLGYBhvfa5hg/featured
I am running into an issue with my program and I can't figure out why, I believe I have narrowed the issue down to the "View" class doesn't not see the "Controller" class to pass the function. I just don't know why. I am doing what I believe to be the same thing as Life in Code is doing with his example.
atdsController.py
import sys
from atdsCreatorUi import displayUi
#from atdsModel import atdsModel
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QMainWindow
class atdsController:
def __init__(self):
#self.model = atdsModel()
self.view = displayUi(self)
def on_button_click(self, btnTxt):
print("I'm back in controller")
#file = self.model.openFile()
def main():
atdsFileCreator = QApplication(sys.argv)
atdsFileCreator.setStyle('Fusion')
#Show GUI
view = displayUi(QMainWindow)
view.show()
sys.exit(atdsFileCreator.exec_())
if __name__ == "__main__":
main()
atdsCreatorUi.
from PyQt5.QtCore import QCoreApplication, QDateTime, QTimer, QMetaObject
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import (
QMainWindow,
QFrame,
QWidget,
QHBoxLayout,
QVBoxLayout,
QGridLayout,
QGroupBox,
QLabel,
QPushButton,
QLineEdit,
QFileDialog,
QTableWidget,
QHeaderView,
QMenuBar,
QProgressBar,
QStatusBar,
QAction,
QWidgetAction,
QToolBar,
QPlainTextEdit)
__version__ = "1.0"
__author__ = "Daniel DeWitte"
ERROR_MSG = 'ERROR'
class VLine(QFrame):
def __init__(self):
super(VLine, self).__init__()
self.setFrameShape(self.VLine|self.Sunken)
class displayUi(QMainWindow):
def _createLeftLayout(self):
leftLayout = QVBoxLayout()
# Create Buttons
loadFile = QPushButton("Load File")
#btnTxt = loadFile.text()
loadFile.clicked.connect(lambda checked, btnTxt = loadFile.text():
self.controller.on_button_click(btnTxt))
loadFile.setFont(QFont('Times', 16))
leftLayout.addWidget(loadFile)
# Create Header Information
header = QGroupBox("Imported File Information:")
header.setObjectName("Header")
header.setStyleSheet("""QGroupBox#Header {border: 1px solid gray;
border-radius: 5px; margin-top: 0.5em;
font-size: 18px; font-weight: bold;}
QGroupBox:title {subcontrol-origin: margin;
subcontrol-position: top center; padding: 0px 0px;}""")
headerInfo = QGridLayout()
# Create QLineEdits()
empNum = QLineEdit()
empNum.setPlaceholderText("Employee Number")
empNum.setReadOnly(True)
empNum.setFixedWidth(200)
file = QLineEdit()
file.setPlaceholderText("File selected for conversion")
file.setReadOnly(True)
file.setFixedWidth(200)
testType = QLineEdit()
testType.setPlaceholderText("Test to be converted")
testType.setReadOnly(True)
testType.setFixedWidth(200)
partNum = QLineEdit()
partNum.setPlaceholderText("Part Number of UUT")
partNum.setReadOnly(True)
partNum.setFixedWidth(200)
serialNum = QLineEdit()
serialNum.setPlaceholderText("Serial Number of UUT")
serialNum.setReadOnly(True)
serialNum.setFixedWidth(200)
testStand = QLineEdit()
testStand.setPlaceholderText("Test stand test was performed on")
testStand.setReadOnly(True)
testStand.setFixedWidth(200)
standCal = QLineEdit()
standCal.setPlaceholderText("Calibration date of Test Stand")
standCal.setReadOnly(True)
standCal.setFixedWidth(200)
swBuildName = QLineEdit()
swBuildName.setPlaceholderText("OFP SW Version")
swBuildName.setReadOnly(True)
swBuildName.setFixedWidth(200)
buildName = QLineEdit()
buildName.setPlaceholderText("Relay Emulator Tools SW Version")
buildName.setReadOnly(True)
buildName.setFixedWidth(200)
buildToolsName = QLineEdit()
buildToolsName.setPlaceholderText("OM Build Tools SW Version")
buildToolsName.setReadOnly(True)
buildToolsName.setFixedWidth(200)
supportBuildName = QLineEdit()
supportBuildName.setPlaceholderText("Support Tools SW Version")
supportBuildName.setReadOnly(True)
supportBuildName.setFixedWidth(200)
numFilesGen = QLineEdit()
numFilesGen.setPlaceholderText("Number of ATDS files to be generated")
numFilesGen.setReadOnly(True)
numFilesGen.setFixedWidth(200)
# Create Layout
headerInfo.addWidget(loadFile, 0, 0, 1, 2)
headerInfo.addWidget(QLabel("Employee Number:"), 1, 0)
headerInfo.addWidget(empNum, 1, 1)
headerInfo.addWidget(QLabel("TDR File:"), 2, 0)
headerInfo.addWidget(tdrFile, 2, 1)
headerInfo.addWidget(QLabel("Test Name:"), 3, 0)
headerInfo.addWidget(testType, 3, 1)
headerInfo.addWidget(QLabel("Part Number:"), 4, 0)
headerInfo.addWidget(partNum, 4, 1)
headerInfo.addWidget(QLabel("Serial Number:"), 5, 0)
headerInfo.addWidget(serialNum, 5, 1)
headerInfo.addWidget(QLabel("Test Stand:"), 6, 0)
headerInfo.addWidget(testStand, 6, 1)
headerInfo.addWidget(QLabel("Test Stand Calibration Date:"), 7, 0)
headerInfo.addWidget(standCal, 7, 1)
headerInfo.addWidget(QLabel("OFP SW Version:"), 8, 0)
headerInfo.addWidget(ofpBuildName, 8, 1)
headerInfo.addWidget(QLabel("Relay Emulator Tools SW Version:"), 9, 0)
headerInfo.addWidget(reBuildName, 9, 1)
headerInfo.addWidget(QLabel("OM Build Tools SW Version:"), 10, 0)
headerInfo.addWidget(omBuildToolsName, 10, 1)
headerInfo.addWidget(QLabel("Support Tools SW Version:"), 11, 0)
headerInfo.addWidget(supportBuildName, 11, 1)
headerInfo.addWidget(QLabel("Number of ATDS Files to be Created:"), 12, 0)
headerInfo.addWidget(numFilesGen, 12, 1)
#headerInfo.setRowStretch(13, 1)
# Add Header to Frame
header.setLayout(headerInfo)
leftLayout.addWidget(header)
convertFile = QPushButton("Convert file to ATDS Format")
#convertFiles.clicked.connect(self.convertFile)
convertFile.setFont(QFont('Times', 16))
leftLayout.addWidget(convertFile)
# Add left layout to Main Layout
self.mainLayout.addLayout(leftLayout, 1)
def _createRightLayout(self):
rightLayout = QVBoxLayout()
#Create ATDS File Table
rightLayout.convTable = QTableWidget()
rightLayout.convTable.setRowCount(12)
rightLayout.convTable.setColumnCount(5)
# Table to fit the screen horizontally
rightLayout.convTable.horizontalHeader().setStretchLastSection(True)
rightLayout.convTable.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
rightLayout.convTable.horizontalHeader().setMinimumSectionSize(115)
# Set Column Names
rightLayout.convTable.setHorizontalHeaderLabels(["ATDS File Name:", "ATDS File Desc:", "Conversion Status:",
"Test Section:","Pass / Fail:"])
rightLayout.addWidget(rightLayout.convTable)
# Detailed information of selected files
#Create ATDS File Table
rightLayout.detailedInfoTable = QTableWidget()
rightLayout.detailedInfoTable.setRowCount(10)
rightLayout.detailedInfoTable.setColumnCount(7)
# Table to fit the screen horizontally
rightLayout.detailedInfoTable.horizontalHeader().setStretchLastSection(True)
rightLayout.detailedInfoTable.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
rightLayout.detailedInfoTable.horizontalHeader().setMinimumSectionSize(115)
# Set Column Names
rightLayout.detailedInfoTable.setHorizontalHeaderLabels(["Test Section:", "Test Description:", "Units:",
"Lower Limit:", "Upper Limit:", "Value:", "Pass / Fail:"])
rightLayout.addWidget(rightLayout.detailedInfoTable)
# Add right layout to Main Layout
self.mainLayout.addLayout(rightLayout, 3)
def findFile(self):
doc = QFileDialog.getOpenFileName(self,
"Load TDR File",
r'S:\\EDE\\adv_sys_mfg',
"Excel Files (*.xls*);; LibreOffice Files (*.ods)")
def _createMenu(self):
menu = QMenuBar(self)
# Create Menus
fileMenu = menu.addMenu("&File")
fileMenu.addAction(self.loadAction)
fileMenu.addSeparator()
fileMenu.addAction(self.quit)
aboutMenu = menu.addMenu("&Help")
self.setMenuBar(menu)
def _createActions(self):
self.loadAction = QAction("&Load New File", self)
self.loadAction.setShortcut("Ctrl+N")
self.loadAction.triggered.connect(self.findFile)
self.quit = QAction("Quit", self)
self.quit.setShortcut("Ctrl+Q")
self.quit.triggered.connect(QCoreApplication.instance().quit)
def _createStatusBar(self):
statusBar = QStatusBar()
# Create Status Bar
statusMsg = "Click Load File or Ctrl + N to begin"
statusBar.showMessage(statusMsg)
statusBar.addPermanentWidget(VLine())
# Create Progress Bar
progressBar = QProgressBar()
statusBar.addPermanentWidget(progressBar)
progressBar.setValue(50)
statusBar.addPermanentWidget(VLine())
# Add Date Time Widget to status bar
self.display = QLabel()
statusBar.addPermanentWidget(self.display)
current = QDateTime.currentDateTime()
self.display.setText(current.toString("yyyy-MMM-dd h:mm:ss AP"))
# Create date and time widget
timer = QTimer()
timer.timeout.connect(self.displayTime)
timer.start(1000)
self.displayTime()
self.setStatusBar(statusBar)
def displayTime(self):
current = QDateTime.currentDateTime()
self.display.setText(current.toString("yyyy-MMM-dd h:mm:ss AP"))
def __init__(self, atdsController):
# View Initializer
super().__init__()
# Connect atdsController
self.controller = atdsController()
# Set Window Properties
self.setWindowTitle("TDR File Conversion to ATDS")
self.setMinimumSize(1250, 600)
# Set Central Widget and general layout
self.mainLayout = QHBoxLayout()
self._centralWidget = QWidget(self)
self.setCentralWidget(self._centralWidget)
self._centralWidget.setLayout(self.mainLayout)
# Create a display and buttons
self._createActions()
self._createLeftLayout()
self._createRightLayout()
self._createMenu()
self._createStatusBar()
When I run this code, I get the following error:
"runfile('H:/C4ISR S2 NPI/Projects/Voice of the Process/ATDS TDR Importer - Python/ATDS File Creator/atdsController.py', wdir='H:/C4ISR S2 NPI/Projects/Voice of the Process/ATDS TDR Importer - Python/ATDS File Creator')
Reloaded modules: atdsCreatorUi
Traceback (most recent call last):
File "H:\C4ISR S2 NPI/Projects/Voice of the Process/ATDS TDR Importer - Python/ATDS File Creator\atdsCreatorUi.py", line 51, in
loadFile.clicked.connect(lambda checked, btnTxt = loadFile.text(): self.controller.on_button_click(btnTxt))
AttributeError: 'QMainWindow' object has no attribute on_button_click'
"
From what it looks like is that atdsCreatorUi is not seeing the atdsController but I don't know why.
Any help will be appreciated,
~Dan

Creating a non-overlapping QVideoPlayer and PlotWidget in PyQt5

I am trying to create an app in PyQt5 that has a media (video) player, a graph, and a few buttons. Currently, whenever I try to add the video and graph widgets, they compete for space (lay on top of one another), even when using QGridLayout.
Here is the entire file so far. The important parts are under 'Create video object', 'Create plot', and 'Create GUI Layout'.
Any suggestions for getting the video player to occupy the top portion of the window and the graph to occupy a region underneath?
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QGridLayout, QFileDialog, QVBoxLayout, QHBoxLayout
from pyqtgraph import PlotWidget
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtCore import QUrl
import sys
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(300, 100, 900, 600)
self.init_gui()
self.show()
def init_gui(self):
# Create media object
self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
# Create video object
self.videoWidget = QVideoWidget()
# Create plot (can't get to size properly)
self.plotWidget = PlotWidget()
# Create 'Video' button
self.videoBtn = QPushButton('Open Video')
self.videoBtn.clicked.connect(self.open_video)
# Create 'Event Index' Button
self.eventIndexBtn = QPushButton('Event Index')
self.eventIndexBtn.setEnabled(False)
self.eventIndexBtn.clicked.connect(self.open_event_times)
# Create 'Time Series' Button
self.timeSeriesBtn = QPushButton('Time Series')
self.timeSeriesBtn.setEnabled(False)
self.timeSeriesBtn.clicked.connect(self.open_time_series)
# Create 'Prev' Button
self.prevBtn = QPushButton('Prev')
self.prevBtn.setEnabled(False)
# Create 'Next' Button
self.nextBtn = QPushButton('Next')
self.nextBtn.setEnabled(False)
# Create 'Replay' Button
self.replayBtn = QPushButton('Replay')
self.replayBtn.setEnabled(False)
# Create file dialog layout
fileBoxLayout = QVBoxLayout()
fileBoxLayout.addWidget(self.videoBtn)
fileBoxLayout.addWidget(self.eventIndexBtn)
fileBoxLayout.addWidget(self.timeSeriesBtn)
# Create controls layout
controlBoxLayout = QHBoxLayout()
controlBoxLayout.addWidget(self.prevBtn)
controlBoxLayout.addWidget(self.nextBtn)
controlBoxLayout.addWidget(self.replayBtn)
# Create GUI layout
GUILayout = QGridLayout()
GUILayout.addWidget(self.videoWidget, 0, 0, 8, 9)
GUILayout.addWidget(self.plotWidget, 8, 0, 2, 9)
GUILayout.addLayout(fileBoxLayout, 10, 0, 2, 3)
GUILayout.addLayout(controlBoxLayout, 10, 3, 2, 6)
self.setLayout(GUILayout)
self.mediaPlayer.setVideoOutput(self.videoWidget)
def open_video(self):
video_dialog = QFileDialog(self)
video_dialog.setNameFilters(["Videos (*.mp4 *.avi *.mov *.flv *.wmv)"])
video_dialog.selectNameFilter("Videos (*.mp4 *.avi *.mov *.flv *.wmv)")
video_dialog.exec_()
video_file_name = video_dialog.selectedFiles()
if len(video_file_name) != 0:
self.eventIndexBtn.setEnabled(True)
# Load first frame
self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(video_file_name[0])))
self.mediaPlayer.setPosition(0)
self.mediaPlayer.play()
self.mediaPlayer.pause()
def open_event_times(self):
event_times_dialog = QFileDialog(self)
event_times_dialog.setNameFilters(["Text (*.csv)"])
event_times_dialog.selectNameFilter("Text (*.csv)")
event_times_dialog.exec_()
event_times_file_name = event_times_dialog.selectedFiles()
if len(event_times_file_name) != 0:
self.timeSeriesBtn.setEnabled(True)
self.nextBtn.setEnabled(True)
def open_time_series(self):
time_series_dialog = QFileDialog(self)
time_series_dialog.setNameFilters(["Text (*.csv)"])
time_series_dialog.selectNameFilter("Text (*.csv)")
time_series_dialog.exec_()
time_series_file_name = time_series_dialog.selectedFiles()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
The problem is that the QVideoWidget at startup does not have to display anything so the sizeHint is (-1x-1) making it occupy the smallest possible size causing the problem you are seeing.
A possible solution is to establish the same stretching factor between rows 0 and 1, it is not necessary nor should you place the proportions in the span, considering the above the solution is:
# Create GUI layout
GUILayout = QGridLayout()
GUILayout.addWidget(self.videoWidget, 0, 0, 1, 9)
GUILayout.addWidget(self.plotWidget, 1, 0, 1, 9)
GUILayout.addLayout(fileBoxLayout, 2, 0, 2, 3)
GUILayout.addLayout(controlBoxLayout, 3, 3, 2, 6)
GUILayout.setRowStretch(0, 1)
GUILayout.setRowStretch(1, 1)

PyQt5 removing QListWidgets and QPushButton dynamically and interact with listItems

Within my QApplication I want to create QListWidgets dynamically and do something with listitems.
I want to create a Favorite Tab. The only think that work is self.listWidget_fav.clear
There are 4 QPushButtons
the self.buttonOK button have to use the list items
the self.buttonRemoveFav has to remove the entire QListWidget with the 4 QPushButtons
the self.buttonDel has to clear the entire list <---- working
the self.buttonDelSel has to remove selected listItem.
What's wrong?
import sys, time, names
from PyQt5 import QtCore
from PyQt5.QtCore import QAbstractTableModel, Qt
from PyQt5.QtWidgets import *
from functools import partial
import names
colPos = 0
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.resize(800, 600)
self.tabs = QTabWidget()
self.tabs.layout = QGridLayout()
self.tabs.setLayout(self.tabs.layout)
self.grid = QGridLayout()
self.grid.addWidget(self.tabs)
self.setLayout(self.grid)
self.setCentralWidget(self.tabs)
self.result = QTabWidget()
self.result.layout = QGridLayout()
self.result.setLayout(self.result.layout)
self.fav = QTabWidget()
self.fav.layout = QGridLayout()
self.fav.setLayout(self.fav.layout)
self.tabs.addTab(self.result, 'Tab 1')
self.tabs.addTab(self.fav, 'Fav')
#create space to put the export button in the bottom of the TableView
positions = [(i,j) for i in range(20) for j in range(10)]
lst = []
for i in range(30):
lst.append(names.get_full_name())
print(lst)
self.checkBoxes = []
for position, no in zip(positions, lst):
self.checkB = QCheckBox(str(no), self)
self.result.layout.addWidget(self.checkB, *position)
self.checkBoxes.append(self.checkB)
#select All
self.buttonSelAll = QPushButton("Select All", self)
self.buttonSelAll.clicked.connect(partial(self.selectBoxes, True))
self.result.layout.addWidget(self.buttonSelAll, 21, 0)
#select All
self.buttonNone = QPushButton("Select None", self)
self.buttonNone.clicked.connect(partial(self.selectBoxes, False))
self.result.layout.addWidget(self.buttonNone, 21, 1)
#select All
self.buttonFav = QPushButton("Fav", self)
self.buttonFav.clicked.connect(self.toFav)
self.result.layout.addWidget(self.buttonFav, 21, 3)
self.checkBtext = [] # var for text of checkboxes.
for i in range(len(self.checkBoxes)):
self.checkBtext.append(self.checkBoxes[i].text())
self.res = {}
def resetColPos(self):
global colPos
colPos = colPos - 2
self.listWidget_fav.hide()
self.buttonOK.hide()
self.buttonDel.hide()
self.buttonDelSel.hide()
self.buttonRemoveFav.hide()
def removeSelfromFav(self):
listItems = self.listWidget_fav.selectedItems()
if not listItems: return
for item in listItems:
self.listWidget_fav.takeItem(self.listWidget_fav.row(item))
def toFav(self):
global colPos
states = [c.isChecked() for c in self.checkBoxes]
self.selectedChecktext = [] #Text of selected checkbox
for key in self.checkBtext:
for value in states:
self.res[key] = value
states.remove(value)
break
print("self.res.items(): ", self.res.items())
print(len(self.res))
for k, v in self.res.items():
if v == True and not k in self.selectedChecktext:
self.selectedChecktext.append(k)
elif v == False and k in self.selectedChecktext:
self.selectedChecktext.remove(k)
print("self.selectedChecktext: ", self.selectedChecktext)
self.listWidget_fav = QListWidget()
self.listWidget_fav.addItems(self.selectedChecktext)
self.fav.layout.addWidget(self.listWidget_fav, 0, colPos, 5, 2)
self.fav.setLayout(self.fav.layout)
self.buttonOK = QPushButton("ok", self)
self.fav.layout.addWidget(self.buttonOK, 6, colPos)
self.fav.setLayout(self.fav.layout)
self.buttonRemoveFav = QPushButton("Remove Fav", self)
self.buttonRemoveFav.clicked.connect(self.resetColPos)
self.fav.layout.addWidget(self.buttonRemoveFav, 6, colPos+1)
self.fav.setLayout(self.fav.layout)
self.buttonDel = QPushButton("Clear List", self)
self.buttonDel.clicked.connect(self.listWidget_fav.clear)
self.fav.layout.addWidget(self.buttonDel, 7, colPos)
self.fav.setLayout(self.fav.layout)
self.buttonDelSel = QPushButton("Delete selected", self)
self.fav.layout.addWidget(self.buttonDelSel, 7, colPos+1)
self.fav.setLayout(self.fav.layout)
colPos = colPos + 2
def checkStates(self):
states = [c.isChecked() for c in self.checkBoxes]
print ("states: ", states)
def selectBoxes(self, state):
for check in self.checkBoxes:
check.blockSignals(True)
check.setChecked(state)
check.blockSignals(False)
self.checkStates()
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyle('Fusion')
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
names Package have to be installed via pip -m install names ;)

How to get the cell position of QCombobox which is a QTableWidgetItem

So the below code is part of a bigger project but in general, I have a QTableWidget which is populated from a database. One of the items is a combobox which when the user selects a milestone option from the combobox I want to be able to know which row and column the combo box that was select is in so I can then apply a fixed rate to the value of a cell in the same row. All I need help on is how to track which cell (row, column) the combo box that was selected is in.
Please note im using other tabs that are not shown and is why my code is setup the way it is. I found some other help but am not a very experience python programmer so I got stuck.
#!/usr/local/bin/python
# -*- coding: latin9 -*-
import sys, os , random
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import pyqtSlot,SIGNAL,SLOT
import time
import json
import openpyxl
import Lists
class CashflowTab(QtGui.QDialog):
'''
Parent for all tab widgets of the REPO GUI
'''
def __init__(self, parent = None):
super(CashflowTab, self).__init__()
if parent != None:
self.setParent(parent)
self.initUI()
self.loadSettings()
def loadSettings(self):
'''
read settings and read db
'''
fh = open('settings.json')
self.settings = json.load(fh)
fh.close()
#load db
dbpath = self.settings['dbpath']
self.db = Lists.SQLiteHandler(dbpath)
self.repo = Lists.WCNList('ROSQL')
try:
self.db.read(self.repo)
except:
pass
class WCNSelectTab(CashflowTab):
'''
Window for WCN selection
'''
def __init__(self, parent = None):
super(WCNSelectTab, self).__init__(parent)
if parent != None:
self.setParent(parent)
def initUI(self):
global wbsitem, WCNSelectTab_object, linequerycheck
linequerycheck = 'False'
wbsitem = 'null'
QtGui.QApplication.setStyle(QtGui.QStyleFactory.create("cleanlooks"))
gbox = QtGui.QGridLayout(self)
self.projectlist = QtGui.QTableWidget()
self.projectlist.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
#self.projectlist.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
self.projectlist.setColumnCount(3)
self.projectlist.setHorizontalHeaderLabels(QtCore.QStringList(['WBS','Service','Milestone']))
self.projectlist.setColumnWidth(0, 100)
self.projectlist.setColumnWidth(1, 100)
self.projectlist.setColumnWidth(2, 150)
gbox.addWidget(self.projectlist,5,0,3,6)
self.getAwardBudget()
def getAwardBudget(self):
global wbs_details
wbs_details = []
wbs_details.append(["123", "Service 1"])
wbs_details.append(["456", "Service 2"])
print wbs_details
self.projectlist.setRowCount(len(wbs_details))
for n,item in enumerate(wbs_details):
qitem = QtGui.QTableWidgetItem(item[0])
self.projectlist.setItem(n, 0, qitem)
qitem = QtGui.QTableWidgetItem(item[1])
self.projectlist.setItem(n, 1, qitem)
milestone_options = ["Award","Mobilization","Survey"]
milestonecombo = QtGui.QComboBox()
for t in milestone_options:
milestonecombo.addItem(t)
milestonecombo.setFixedWidth(150)
self.projectlist.setCellWidget(n, 2, milestonecombo)
class RepoGUI(QtGui.QMainWindow):
'''
Main Widget for REPO helper
'''
def __init__(self):
super(RepoGUI, self).__init__()
#self.mode = mode
self.initUI()
def initUI(self):
global approval, approval_names, username, approval_names
self.tabs = QtGui.QTabWidget()
self.setCentralWidget(self.tabs)
self.tabs.setAutoFillBackground(1)
fh = open('settings.json')
settings = json.load(fh)
fh.close()
if settings['WCNsubmit'] == 1:
self.tabs.addTab(WCNSelectTab(), 'WCN Creation')
self.setWindowTitle('Work Completion Notification')
self.setGeometry(300, 150, 1400, 800)
self.setStyleSheet('font-size: %ipt' %settings['fontsize'])
self.show()
def main():
app = QtGui.QApplication(sys.argv)
ex = RepoGUI()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
A possible solution is to use indexAt() since the position of the QComboBox is relative to the viewport(), but to obtain the QComboBox that was selected we use sender().
for n,item in enumerate(wbs_details):
qitem = QtGui.QTableWidgetItem(item[0])
self.projectlist.setItem(n, 0, qitem)
qitem = QtGui.QTableWidgetItem(item[1])
self.projectlist.setItem(n, 1, qitem)
milestone_options = ["Award","Mobilization","Survey"]
milestonecombo = QtGui.QComboBox()
milestonecombo.addItems(milestone_options)
milestonecombo.setFixedWidth(150)
milestonecombo.currentIndexChanged[str].connect(self.onCurrentIndexChanged)
self.projectlist.setCellWidget(n, 2, milestonecombo)
def onCurrentIndexChanged(self, text):
combobox = self.sender()
ix = self.projectlist.indexAt(combobox.pos())
print(ix.row(), ix.column(), text)
Another possible solution is to use the property:
for n,item in enumerate(wbs_details):
qitem = QtGui.QTableWidgetItem(item[0])
self.projectlist.setItem(n, 0, qitem)
qitem = QtGui.QTableWidgetItem(item[1])
self.projectlist.setItem(n, 1, qitem)
milestone_options = ["Award","Mobilization","Survey"]
milestonecombo = QtGui.QComboBox()
milestonecombo.addItems(milestone_options)
milestonecombo.setFixedWidth(150)
milestonecombo.setProperty("row", n)
milestonecombo.setProperty("column", 1)
milestonecombo.currentIndexChanged[str].connect(self.onCurrentIndexChanged)
self.projectlist.setCellWidget(n, 2, milestonecombo)
def onCurrentIndexChanged(self, text):
combobox = self.sender()
r = combobox.property("row").toPyObject()
c = combobox.property("column").toPyObject()
print(r, c, text)

Why PyQt QGridLayout does not resize?

I'm writing simple calculator by using PyQt. In my code I'm using QGridLayout to compound widgets. But there is a problem. I can't find a way to resize widgets. I tryed to using QWidget.resize and insertStreach, but it's does not work like i need to. Which function can substitute QWidget.resize?
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
class Button(QPushButton):
def __init__(self, text, parent, TextObject):
super().__init__(text, parent=parent or None)
self.clicked.connect(TextObject.SLOT_TextInsert('%s' %(text)))
class Text(QLineEdit):
def __init__(self, parent):
super().__init__(parent=parent)
self.show()
def SLOT_TextInsert(self, text):
return lambda: self.insert('%s' %(text))
def SLOT_TextGet(self):
text = self.text()
if __name__ == '__main__':
app = QApplication(sys.argv)
root = QWidget()
text = Text(root)
plus = Button('+', root, text)
minus = Button('-', root, text)
multiple = Button('*', root, text)
divide = Button('/', root, text)
null = Button('0', root, text)
dot = Button('.', root, text)
equal = Button('=', root, text)
clean = Button('Ce', root, text)
layout = QGridLayout(root)
layout.setSpacing(2)
layout.addWidget(text, 1, 1, 1, 5)
layout.addWidget(plus, 2, 4)
layout.addWidget(minus, 2, 5)
layout.addWidget(multiple, 3, 4)
layout.addWidget(divide, 3, 5)
layout.addWidget(clean, 4, 4, 1, 2)
layout.addWidget(null, 5, 1, 1, 2)
layout.addWidget(dot, 5, 3)
layout.addWidget(equal, 5, 4, 1, 2)
num_list = list()
row=2; col=1
for i in range(0,9):
num_list.append(Button('%s' %(i+1), root, text))
layout.addWidget(num_list[i], row, col )
col = col+1
if i == 2 or i == 5:
col = 1; row = row+1
root.resize(10,10)
root.show()
sys.exit(app.exec_())
See QWidget::sizePolicy:
Button-like widgets set the size policy to specify that they may stretch horizontally, but are fixed vertically.
In order to make the buttons also resize vertically, you need to modify the size policy of your buttons:
class Button(QPushButton):
def __init__(self, text, parent, TextObject):
super().__init__(text, parent=parent or None)
self.setSizePolicy ( QSizePolicy.Expanding, QSizePolicy.Expanding)
self.clicked.connect(TextObject.SLOT_TextInsert('%s' %(text)))

Categories

Resources