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

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)

Related

Retrieve data from a dialog in the calling window

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).

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 ;)

QLabel not displaying in QWidget window

I have the below piece of code which gives the below picture.
import os
import numpy as np
from PyQt5 import QtCore, QtWidgets
import sqlite3
class Ui_Form():
def __init__(self):
#Checking if the loading database is in place
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')
#Asking the user for the input file to be parsed and the number of componenets determined
filePath, _ = QtWidgets.QFileDialog.getOpenFileName(None, "Select input model","","Input deck (*.inp)","*.inp")
filePath = str(filePath)
self.pleaseWait = waitWindow()
self.pleaseWait.show()
#If no file has been inputted the script will exit
if not filePath:
exit()
else:
#If a file has been inputted now it will be opened and a list containing all the lines will be created
readInputFile(filePath)
#Searching in the file for all the valid components. We disregards collectors containing RBE3 elements
#as they don't require fatigue analysis
self.pleaseWait.close()
for line in model_file:
if "*ELEMENT," in line and "DCOUP3D" not in line:
#If a valid collector is found it will be added to the array of type numpy.
try:
#Checks if the collector has already been recorded as different element types partaining of the same component
#will be specified in different collectors win the input deck
if not line.split("ELSET=")[1][:-1] in self.collector_array:
self.collector_array = np.concatenate((self.collector_array,np.array([line.split("ELSET=")[1][:-1]])),axis=0)
except:
self.collector_array = np.array([line.split("ELSET=")[1][:-1]])
#model_file_obj.close
#Testing to see if the array has been created indicating the presence of at least one entity
#This will be useful if the user loads a load deck instead of a model as they have the same .inp extension
try:
self.collector_array
except:
QtWidgets.QMessageBox.information(None,'Error','File contains no element collectors')
#Creating the initial Window
self.mainWidget = QtWidgets.QWidget()
self.mainWidget.resize(500, 500)
self.mainWidget.setWindowFlags(self.mainWidget.windowFlags() | QtCore.Qt.MSWindowsFixedSizeDialogHint)
self.mainWidget.setWindowTitle("nCode analysis set-up")
#Creating the top level grid layout
self.mainGrid = QtWidgets.QGridLayout(self.mainWidget)
#Creating the boxes which will describe the analysis to be written in the .dcl file
self.analysis_type_label = QtWidgets.QLabel(self.mainWidget)
self.analysis_type_label.setText("Type of analysis")
self.mainGrid.addWidget(self.analysis_type_label,0,0)
self.analysis_type_combo = QtWidgets.QComboBox(self.mainWidget)
self.analysis_type_combo.addItems(["Fatigue","Proof plus fatigue"])
self.mainGrid.addWidget(self.analysis_type_combo,0,1,1,2)
self.load_deck_type_label = QtWidgets.QLabel(self.mainWidget)
self.load_deck_type_label.setText("Type of fatigue deck")
self.mainGrid.addWidget(self.load_deck_type_label,1,0)
self.load_deck_type_combo = QtWidgets.QComboBox(self.mainWidget)
self.load_deck_type_combo.addItems(["Regen braking","No regen braking"])
self.mainGrid.addWidget(self.load_deck_type_combo,1,1,1,2)
self.analysis_engine_type_label = QtWidgets.QLabel(self.mainWidget)
self.analysis_engine_type_label.setText("Analysis Engine")
self.mainGrid.addWidget(self.analysis_engine_type_label,2,0)
self.analysis_engine_type_combo = QtWidgets.QComboBox(self.mainWidget)
self.analysis_engine_type_combo.addItems(["EN analysis","SN analysis"])
self.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.mainWidget)
#The line below is absolutely required to make the scrollable area work.
self.scrollArea.setWidgetResizable(True)
self.mainGrid.addWidget(self.scrollArea,3,0,1,3)
self.secondaryWidget = QtWidgets.QWidget()
self.scrollArea.setWidget(self.secondaryWidget)
self.secondaryGrid = QtWidgets.QGridLayout(self.secondaryWidget)
#This bit creates the necessary object for every componenet that was found in the input deck.
#The globals method is used to dynamically assign objects to variables for subsequent manipulation.
for i in range(0, self.collector_array.shape[0]):
globals()["self.materialLabel"+str(i)] = QtWidgets.QLabel(self.secondaryWidget)
globals()["self.materialLabel"+str(i)].setText(self.collector_array[i]+" material")
self.secondaryGrid.addWidget(globals()["self.materialLabel"+str(i)],2+i,0)
globals()["self.materialName"+str(i)] = QtWidgets.QLineEdit(self.secondaryWidget)
globals()["self.materialName"+str(i)].setPlaceholderText("Drop material name here")
globals()["self.materialName"+str(i)].setFixedWidth(150)
self.secondaryGrid.addWidget(globals()["self.materialName"+str(i)],2+i,1)
globals()["self.materialPickingButton"+str(i)] = QtWidgets.QPushButton(self.secondaryWidget)
globals()["self.materialPickingButton"+str(i)].setText("Pick material")
globals()["self.materialPickingButton"+str(i)].clicked.connect(self.material_lookup)
self.secondaryGrid.addWidget(globals()["self.materialPickingButton"+str(i)],2+i,2)
#Creates the button that connects to the DLC_writer function
self.createDCL = QtWidgets.QPushButton(self.mainWidget)
self.createDCL.setText("Create DCL")
self.mainGrid.addWidget(self.createDCL,4,0,1,3)
self.createDCL.clicked.connect(self.DCL_guide)
self.mainWidget.show()
class waitWindow(QtWidgets.QDialog):
def __init__(self):
super().__init__()
self.setWindowTitle("Info")
self.resize(600,200)
self.VLayout = QtWidgets.QVBoxLayout(self)
self.message = QtWidgets.QLabel(self)
self.message.setFixedWidth(550)
self.message.setText("Please wait while input file is being read")
self.VLayout.addWidget(self.message)
class readInputFile():
def __init__(self,filePath):
model_file_obj = open(filePath, "r")
globals()['model_file'] = model_file_obj.readlines()
model_file_obj.close
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
ui = Ui_Form()
sys.exit(app.exec_())
The problem is my text label is missing from this window. I made it so big in case the label did not have enough space to fully display but in that case I think it would have displayed what it had space for. Hopefully someone knows why.
Edit: I have included the entire init function of Ui_Form. All my problems are caused in this bit the rest working ok.
The window you are viewing is not pleaseWait window but the mainWidget window.
The above is explained assuming that:
The file that is read is small, so the pleaseWait window will open and close instantly, so that being that synchronous action Qt will not have time to do it and for the user the window will never have been shown. For this case the solution is to give a reasonable time for the user to see the window.
The file is very large, the reading will take a long time blocking the eventloop, which will cause tasks such as displaying a window to not be performed, to avoid blocking the task must be executed in another thread.
Combining both solutions we obtain the following code:
import os
from functools import partial
from PyQt5 import QtCore, QtWidgets
class Worker(QtCore.QObject):
finished = QtCore.pyqtSignal()
contentChanged = QtCore.pyqtSignal(list)
#QtCore.pyqtSlot(str)
def read_file(self, fileName):
with open(fileName, "r") as model_file_obj:
model_file = model_file_obj.readlines()
print(model_file)
self.contentChanged.emit(model_file)
self.finished.emit()
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")
mainGrid = QtWidgets.QGridLayout(self)
thread = QtCore.QThread(self)
thread.start()
self.m_worker = Worker()
self.m_worker.moveToThread(thread)
self.m_worker.contentChanged.connect(self.get_content)
def launch_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"
)
fileName, _ = QtWidgets.QFileDialog.getOpenFileName(
None, "Select input model", "", "Input deck (*.inp)", "*.inp"
)
self.pleaseWait = WaitWindow()
self.pleaseWait.show()
self.m_worker.finished.connect(self.pleaseWait.close)
wrapper = partial(self.m_worker.read_file, fileName)
# Launch the task in a reasonable time for the window to show
QtCore.QTimer.singleShot(100, wrapper) #
#QtCore.pyqtSlot(list)
def get_content(self, lines):
print(lines)
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)
self.message.setFixedWidth(550)
self.message.setText("Please wait while input file is being read")
layout.addWidget(self.message)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWidget()
w.show()
w.launch_task()
sys.exit(app.exec_())
Update:
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)
#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.show()
w.start_task()
sys.exit(app.exec_())
This code works perfectly for me:
import sys
from PyQt5 import QtWidgets
from PyQt5.Qt import QApplication
class waitWindow(QtWidgets.QDialog):
def __init__(self):
super().__init__()
self.setWindowTitle("Info")
self.resize(600,200)
self.VLayout = QtWidgets.QVBoxLayout(self)
self.message = QtWidgets.QLabel(self)
self.message.setFixedWidth(550)
self.message.setText("Please wait while input file is being read")
self.VLayout.addWidget(self.message)
self.show()
def closeWindow(self):
self.close()
app = QApplication(sys.argv)
w = waitWindow()
w.exec_()
Okay took your code and gutted all the unessential stuff to analyze the actual issue I have included the gutted version so you can see what is necessary in the future to see what is wrong.
In short the issue is that you need to add the following line as the last line in your waitWindow function >> self.exec() by adding that I got your label to display (see code below)
Now with that said you do have another issue and that is the QDialog box will not allow the program to continue until it has been closed (aka it stops the process flow until you release it by closing the window or use a different means). My question is why not use your "main window" to display that message then repopulate with the rest of that data. Also curious why are you not using QMainWindow?
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class Ui_Form():
def __init__(self):
self.pleaseWait = waitWindow()
self.pleaseWait.show()
self.pleaseWait.close()
sys.exit()
class waitWindow(QDialog):
def __init__(self):
super(waitWindow, self).__init__()
self.setWindowTitle("Info")
self.resize(600,200)
self.message = QLabel(self)
self.message.setFixedWidth(550)
self.message.setText("Please wait while input file is being read")
self.VLayout = QVBoxLayout(self)
self.VLayout.addWidget(self.message)
self.setLayout(self.VLayout)
self.exec_()
if __name__ == "__main__":
app = QApplication(sys.argv)
ui = Ui_Form()
sys.exit(app.exec_())

PyQt5 QtreeWidget : How can i access a custom widget's methods in a QtreeWidgetItem?

I have a simple QTreeWidget :
self.treeWidget = QTreeWidget(self)
col = ("Status", "Name")
self.treeWidget.setColumnCount(2)
self.treeWidget.setHeaderLabels(col)
witch I populate using :
wid = Custom_Widget()
item = QTreeWidgetItem(self.treeWidget)
item.setText(1, "some string")
item.treeWidget().setItemWidget(item, 0, wid)
I can easly acces the text column by using :
root = self.treeWidget.invisibleRootItem()
it = root.child(2) # for example the third item
it.setText(1, "Edited")
what i need is to edit the costum_widget in column 0, so how can i access it or invoke his methods ?
I resolved the issue by keeping a list of all the costum_widgets that i create, my code would be :
from CustomWidgets import Custom_Widget
from PyQt5.QtWidgets import *
import sys
class MyExample(QWidget):
def __init__(self):
super().__init__()
self.treeWidget = QTreeWidget(self)
self.group_wid = [] # my list of widgets
col = ("Status", "Name")
self.treeWidget.setColumnCount(2)
self.treeWidget.setHeaderLabels(col)
self.populate_tree()
self.edit_tree()
self.show()
def populate_tree(self):
for i in range(10):
wid = Custom_Widget()
self.group_wid.append(wid) # each time i instantiate a Custom_Widget i'll add it to my list of widgets
item = QTreeWidgetItem(self.treeWidget)
item.setText(1, "some string")
item.treeWidget().setItemWidget(item, 0, wid)
def edit_tree(self):
root = self.treeWidget.invisibleRootItem()
it = root.child(2) # for example the third item
it.setText(1, "Edited")
self.group_wid[2].my_method() # i can easily edit my widgets that are in the QTreeWidget
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MyExample()
app.exec_()
Guess the QtreeWidgetItem only hold a reference to the widgets that are contained.

Python GTK+ 3: How to set row in TreeView active

I have a Gtk.ComboBoxText that should be used as a trigger to activate a row in a Gtk.TreeView. I know how to trigger the combo box by activating the respective row in the tree view. But vice versa is beyond my scope. I learned that I need to pass Gtk.TreePath and Gtk.TreeViewColumn to the function row_activated(), but I don't know how to implement these correctly and where to put the row ID in my function self.combo_changed(). This is an example of the issue:
from gi.repository import Gtk
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
self.set_default_size(200, 100)
self.set_border_width(10)
self.grid = Gtk.Grid(row_spacing=10)
self.add(self.grid)
self.combo = Gtk.ComboBoxText()
self.combo.connect("changed", self.combo_changed)
self.grid.attach(self.combo, 0, 0, 1, 1)
self.liststore = Gtk.ListStore()
self.liststore.set_column_types([int, str])
self.treeview = Gtk.TreeView(self.liststore)
self.treeview.set_activate_on_single_click(True)
self.treeview.connect('row-activated', self.list_changed)
self.grid.attach(self.treeview, 0, 1, 1, 1)
cols = ["ID", "Animal"]
self.treeviewcolumn = []
self.cellrenderertext = []
for i in range(len(cols)):
self.cellrenderertext.append(Gtk.CellRendererText())
self.treeviewcolumn.append(Gtk.TreeViewColumn(cols[i]))
self.treeviewcolumn[i].pack_start(self.cellrenderertext[i], True)
self.treeviewcolumn[i].add_attribute(self.cellrenderertext[i], "text", i)
self.treeview.append_column(self.treeviewcolumn[i])
animals = ["Dog", "Cat", "Mouse"]
self.rowiter = []
for i in range(len(animals)):
self.combo.append_text(animals[i])
self.rowiter.append([self.liststore.append([i, animals[i]])])
self.combo.set_active(0)
def list_changed(self, widget, row, data2):
self.combo.set_active(int(row.to_string()))
def combo_changed(self, widget):
print(widget.get_active()) # the ID of the requested row
#self.treeview.row_activated(Gtk.TreePath(), Gtk.TreeViewColumn())
def quit_window(self, widget, data=None):
Gtk.main_quit()
win = MainWindow()
win.show_all()
win.connect("delete-event", win.quit_window)
Gtk.main()
I discovered that I also need Gtk.TreeView.set_cursor() to achieve my goal:
def combo_changed(self, widget):
row = widget.get_active() # the ID of the requested row
print(row)
self.treeview.row_activated(Gtk.TreePath(row), Gtk.TreeViewColumn(None))
self.treeview.set_cursor(Gtk.TreePath(row))

Categories

Resources