I created a QTreeWidget now when i click on an item, i want to get the widget data.
I fill my QTreeWidget that way :
def addNodeToTreeview(self, data):
self.panelInfoPatientUi.treeWidgetDevices.clear()
for item in data:
mainWidgetItem = QtGui.QTreeWidgetItem(self.panelInfoPatientUi.treeWidgetDevices)
widgetContainer = QtWidgets.QWidget()
widgetContainer.setObjectName("widgetContainer")
deviceWidget = Ui_DeviceListviewWidget()
deviceWidget.setupUi(widgetContainer)
deviceWidget.labelSerialNumber.setText(item.serialNumber)
deviceWidget.labelModel.setText(item.model)
deviceWidget.labelInstallationDate.setText(item.installDate)
mainWidgetItem.setSizeHint(0, widgetContainer.sizeHint())
self.panelInfoPatientUi.treeWidgetDevices.addTopLevelItem(mainWidgetItem)
self.panelInfoPatientUi.treeWidgetDevices.setItemWidget(mainWidgetItem, 0, widgetContainer)
for files in item.listFile:
#Files
fileWidgetItem = QtGui.QTreeWidgetItem(mainWidgetItem)
widgetContainerFiles = QtWidgets.QWidget()
widgetContainerFiles.setObjectName("widgetContainerFiles")
fileWidget = Ui_FileListWidgetItem()
fileWidget.setupUi(widgetContainerFiles)
fileWidgetItem.setText(0, "BLABLBALA")
fileWidget.labelFileName.setText(files.fileName)
fileWidget.labelDateFile.setText(files.dateFile)
fileWidgetItem.setSizeHint(0, widgetContainerFiles.sizeHint())
mainWidgetItem.addChild(fileWidgetItem)
self.panelInfoPatientUi.treeWidgetDevices.setItemWidget(fileWidgetItem, 0, widgetContainerFiles)
i connect the widget that way :
def connectSignalTreeWidget(self):
self.view.panelInfoPatientUi.treeWidgetDevices.itemDoubleClicked.connect(self.testest)
and when i receive the Click event i can't access to my widget i tried several way :
def testest(self, item, col):
print(self.view.panelInfoPatientUi.treeWidgetDevices.itemWidget(item, 0))
#print([method for method in dir(item) if callable(getattr(item, method))])
#print(str(item.ItemType()))
#print(str(item.text(col)))
#print(str(item.child(0)))
#print(str(item.childCount()))
#print(str(item.child(1).text(0)))
#print(str(self.view.panelInfoPatientUi.treeWidgetDevices.currentItem()))
# titi = .itemWidget(item, columnIndex)
# print(str(titi))
# titi.text(0)
# titi.data()
#print(str(titi.labelFileName.text()))
'''selectedItems = self.view.panelInfoPatientUi.treeWidgetDevices.selectedItems()
for selectedItem in selectedItems:
print(str(selectedItem.text(0)))
print(str(selectedItem.text(1)))
print(str(selectedItem.text(2))) '''
'''
print(item.data(1, 0))
print("column count " + str(data.columnCount()))
print("AHYAAAAAAAAAA")'''
As i use "setItemWidget" method i expect to get a getItemWidget method and retreive data from it but no. How can i access to fileWidget.labelFileName ?
Thanks
I found the solution :
I changed my creation methode :
def addNodeToTreeview(self, data):
self.panelInfoPatientUi.treeWidgetDevices.clear()
for item in data:
mainWidgetItem = QtGui.QTreeWidgetItem(self.panelInfoPatientUi.treeWidgetDevices)
widgetContainer = QtWidgets.QWidget()
widgetContainer.setObjectName("widgetContainer")
deviceWidget = Ui_DeviceListviewWidget()
deviceWidget.setupUi(widgetContainer)
deviceWidget.labelSerialNumber.setText(item.serialNumber)
deviceWidget.labelModel.setText(item.model)
deviceWidget.labelInstallationDate.setText(item.installDate)
mainWidgetItem.setSizeHint(0, widgetContainer.sizeHint())
self.panelInfoPatientUi.treeWidgetDevices.addTopLevelItem(mainWidgetItem)
self.panelInfoPatientUi.treeWidgetDevices.setItemWidget(mainWidgetItem, 0, widgetContainer)
for files in item.listFile:
#Files
fileWidgetItem = QtGui.QTreeWidgetItem(mainWidgetItem)
widgetContainerFiles = QtWidgets.QWidget()
widgetContainerFiles.setObjectName("widgetContainerFiles")
widgetContainerFiles.ui = Ui_FileListWidgetItem()
widgetContainerFiles.ui.setupUi(widgetContainerFiles)
widgetContainerFiles.ui.labelFileName.setText(files.fileName)
widgetContainerFiles.ui.labelDateFile.setText(files.dateFile)
fileWidgetItem.setSizeHint(0, widgetContainerFiles.sizeHint())
mainWidgetItem.addChild(fileWidgetItem)
self.panelInfoPatientUi.treeWidgetDevices.setItemWidget(fileWidgetItem, 0, widgetContainerFiles)
and i can get my data like that :
def testest(self, item, col):
print(str(item.treeWidget().itemWidget(item, col).ui.labelFileName.text()))
Related
In my project there is a window for editing files. Each file has some properties that the user can change with several checkboxes. Also each file has an icon.
Now it is implemented through QScrollArea in which widgets are added. It looks like this:
Now I want to add folder support for files. I would like to support drag n drop and so on.
I thought it would be a good idea in my case to use QTreeView.
The widget for the files has already been drawn and it suits me completely:
I haven't worked with QT's model/view framework before. after a couple of days of trying to draw something acceptable, I broke my brain. That's what I did:
import sys
from PySide6.QtWidgets import *
from PySide6.QtGui import *
from PySide6.QtCore import *
from scanner.models import *
from gui.styles.settings import *
from gui.utils import setup_fonts
class BaseFileItem(QStandardItem):
def __init__(self, parent=None):
super(BaseFileItem, self).__init__(parent)
self.setEditable(False)
class TitleItem(QStandardItem):
file_type = 'title'
class FolderItem(QStandardItem):
file_type = 'folder'
class PreviewItem(BaseFileItem):
file_type = 'preview'
class FileItem(BaseFileItem):
file_type = 'file'
class Model(QStandardItemModel):
def supportedDropActions(self):
return Qt.MoveAction
class Delegate(QStyledItemDelegate):
checkbox_width = 50
checkboxes = [
'main',
'preview',
'use',
]
def sizeHint(self, option, index):
match index.data(1002):
case 'title':
height = 32
case 'folder':
height = 24
case _:
height = 48
return QSize(height, height)
def paint(self, painter, option, index):
super(Delegate, self).paint(painter, option, index)
match index.data(1002):
case 'title':
item_type = 'label'
case 'folder':
return
case _:
item_type = 'checkbox'
for column, name in enumerate(self.checkboxes):
self.add_checkbox_item(painter, option, column, name, item_type)
def add_checkbox_item(self, painter, option, column, text, item_type):
rect = option.rect
if item_type == 'checkbox':
item = QStyleOptionButton()
ce = QStyle.CE_CheckBox
else:
item = QStyleOptionHeader()
item.text = text
ce = QStyle.CE_HeaderLabel
item.item_type = item_type
x, y = rect.left() + rect.width() - (column + 1) * self.checkbox_width, rect.top()
item.rect = QRect(x, y, self.checkbox_width, rect.height())
QApplication.style().drawControl(ce, item, painter)
class AssetEditFilesView(QWidget):
rows = ['Asset files', 'Previews', 'Candidates']
def __init__(self, files, parent=None):
self.files = files
super(AssetEditFilesView, self).__init__(parent)
self.setContentsMargins(24, 24, 24, 24)
self.model = Model()
self.tree = QTreeView(self)
self.tree.setContentsMargins(4, 4, 4, 4)
self.tree.setItemDelegate(Delegate(self.tree))
self.tree.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.tree.setSortingEnabled(True)
self.tree.setDragEnabled(True)
self.tree.setAcceptDrops(True)
self.tree.setDropIndicatorShown(True)
self.tree.header().hide()
self.tree.setModel(self.model)
self.import_data(files)
self.tree.expandAll()
layout = QVBoxLayout(self)
layout.addWidget(self.tree)
def import_data(self, data):
self.model.setRowCount(0)
for group, files in zip(self.rows, self.prepare_files(data)):
if files:
self.add_files_to_group(group, files)
def add_files_to_group(self, group, files):
files = sorted(files, key=lambda x: str(x.data().asset_path))
data = [f.data().asset_path.parts for f in files]
max_len = max([len(x) for x in data])
prepared = [x for x in zip(*[[y[i] if i < len(y) else None for i in range(max_len)] for y in data])]
structure = self.create_structure(prepared, files)
root = self.add_file_row(self.model.invisibleRootItem(), group, TitleItem)
for folder, items in structure.items():
file_model = PreviewItem if group == 'Previews' else FileItem
self.add_items(root, folder, items, file_model=file_model)
def add_items(self, root, folder, items, file_model=FileItem):
if folder == '.':
for item in items:
self.add_file_row(root, item, file_model)
else:
new_root = self.add_file_row(root, folder, FolderItem)
for _folder, _items in items.items():
self.add_items(new_root, _folder, _items, file_model=file_model)
def add_file_row(self, root, item, file_model):
item_name = str(item.filename.name) if hasattr(item, 'filename') else item
item_model = file_model(item_name)
item_model.setData(item, 1001)
item_model.setData(file_model.file_type, 1002)
print(root)
root.appendRow(item_model)
return item_model
def create_structure(self, prepared, files):
structure = {'.': []}
for *parts, file in zip(*prepared, [f.data() for f in files]):
parts = list(filter(lambda x: x is not None, parts))
parent = structure
for part in parts:
if part not in parent:
parent[part] = {'.': []}
parent = parent[part]
parent['.'].append(file)
return structure
def prepare_files(self, data):
groups = [[], [], []]
for file in data:
if type(file) in [PreviewImage, PreviewVideo]:
group = 1
elif isinstance(file, BaseFileModel):
group = 0
else:
group = 2
item = QStandardItem(str(file.filename.name))
item.setData(file)
groups[group].append(item)
return groups
style = f'''
AssetEditFilesView QTreeView {{
{Fonts.normal}
border: 2px;
border-radius: 8px;
background-color: {Colors.asset_edit_bg};
}}
AssetEditFilesView {{
background-color: {Colors.popup_bg};
}}
AssetEditFilesView {{
background-color: {Colors.popup_bg};
'''
if __name__ == '__main__':
files = [
BaseFileModel(filename=r'c:\temp0036.png'),
BaseFileModel(filename=r'c:\temp0036.png'),
BaseFileModel(filename=r'c:\temp0036.png', asset_path=Path('./huita/huyatina')),
BaseFileModel(filename=r'c:\temp0048.png', asset_path=Path('./huita')),
BaseFileModel(filename=r'c:\temp0127.png', asset_path=Path('./ne_huita')),
BaseFileModel(filename=r'c:\temp0229.png', asset_path=Path('./ne_huita/huiyatina')),
PreviewVideo(filename=r'c:\references.gif', asset_path=Path('./previews')),
PreviewImage(filename=r'c:\temp321.png', asset_path=Path('./previews')),
PreviewImage(filename=r'c:\temp0267.png', asset_path=Path('./previews/generated')),
PreviewImage(filename=r'c:\temp3.png', asset_path=Path('./previews/generated/1/2')),
PreviewImage(filename=r'c:\temp.bin', asset_path=Path('./previews')),
PreviewImage(filename=r'c:\temp.bin.png', asset_path=Path('./previews')),
PreviewImage(filename=r'c:\temp.png', asset_path=Path('./previews/generated/2/1')),
PreviewImage(filename=r'c:\temp.png', asset_path=Path('./previews/generated/1/2')),
PreviewImage(filename=r'c:\temp.png', asset_path=Path('./previews/generated/1')),
]
app = QApplication(sys.argv)
setup_fonts(app)
app.setStyleSheet(style)
view = AssetEditFilesView(files)
view.setGeometry(800, 500, 800, 640)
view.setWindowTitle('QTreeview Example')
view.show()
sys.exit(app.exec())
I have 3 entities:
file (should look like on the 1st screenshot (3 checkboxes and an icon))
folder (must contain a name)
title (in fact the folder only the font should be larger)
how do i implement all entities using 1 QStyledItemDelegate?
Can I use a ready-made custom QWidget as a file entity?
the only thing I managed to do was to implement a more or less working sizeHint, but I have no idea how to add a file widget.
I will be grateful for any help, as now I am close to implementing all this through QScrollArea instead of QTreeView
i need some thing like this:
I also can't figure out how to apply styles to a QStandardItem, QStyledItemDelegate,
Basically, I have a QTableView and the last column of each row contains a QMenu where if triggered, the row should be deleted. I tried the code below, but if I click on the menu that is in a row number > 1, the returned rowNum is -1:
Code:
def addrowIntable(self, a, b):
Column1 = QStandardItem("%s" % (a))
Column2 = QStandardItem("%s" % (b))
actionBTN = QPushButton("")
actionMenu = QMenu()
self.RemList = QtWidgets.QAction("Remove row", actionMenu)
actionMenu.addAction(self.RemList)
actionMenu.raise_()
actionBTN.setMenu(actionMenu)
self.rulesWhitelistWidgetModel.appendRow([Column1, Column2])
self.rulesWhiteListFileTBL.setIndexWidget(
self.rulesWhitelistWidgetModel.index(self.rulesWhitelistWidgetModel.rowCount() - 1,
self.rulesWhiteListFileTBL.model().columnCount() - 1), actionBTN)
self.RemList.triggered.connect(lambda: self.deleteRow("Hello"))
def deleteRow(self, str):
rowNum = self.rulesWhiteListFileTBL.rowAt(self.rulesWhiteListFileTBL.viewport().mapFromGlobal(self.sender().parent().pos()).y())
print(self.rulesWhiteListFileTBL.indexAt(self.sender().parent().pos()).row())
print(rowNum)
I just need to know which row number was the sender from inside deleteRow where I could then use model.removeRow() to delete it.
The main reason why your code doesn't work as expected is because you set the menu as the parent of the action. A menu is a popup window, so its position will be in global coordinates, whereas you want the position relative to the table. A simple way to achieve this is to make the button the parent of the action instead.
The following revision of your code should do what you want:
def addrowIntable(self, a, b):
Column1 = QStandardItem("%s" % (a))
Column2 = QStandardItem("%s" % (b))
actionBTN = QPushButton()
actionMenu = QMenu()
actionRem = QtWidgets.QAction("Remove row", actionBTN)
actionMenu.addAction(actionRem)
actionBTN.setMenu(actionMenu)
self.rulesWhitelistWidgetModel.appendRow([Column1, Column2])
self.rulesWhiteListFileTBL.setIndexWidget(Column2.index(), actionBTN)
actionRem.triggered.connect(lambda: self.deleteRow("Hello"))
def deleteRow(self, str):
pos = self.sender().parent().pos()
index = self.rulesWhiteListFileTBL.indexAt(pos)
self.rulesWhitelistWidgetModel.removeRow(index.row())
The code bellow try to embed visvis figure in a wx application to make a movie with 3D data. The problem is that everytime I rum the code, I get the error
"./src/unix/glx11.cpp(86): assert "xid" failed in SetCurrent(): window
must be shown" right after calling Figure = app.GetFigureClass()
self.fig = Figure(self)
I spent some time researching this error, but none of the answers suited me. Does anyone knows how to fix it?
import wx
import h5py
import numpy as np
import visvis as vv
app = vv.use('wx')
class CPlot3D (wx.Frame) :
"""
Class for plotting 3D Dirac
"""
def data_for_plotting (self, frame_number) :
"""
Load the data to be plotted for the frame with the frame_number
"""
frame = str(self.frame_names[frame_number])
return self.f[frame][...]
def draw_curent_frame (self, event=None) :
"""
Display the current frame
"""
# Load data
data = self.data_for_plotting (self.frame_number.GetValue())
try :
self.volume_plot.SetData (data)
except AttributeError :
vv.clf()
self.volume_plot = vv.volshow (data, clim=(self.global_min, self.global_max), renderStyle='mip', cm=vv.CM_JET)
a = vv.gca()
vv.ColormapEditor(a)
def GetTicks (axis_num, min_val, max_val, label_format="%.2f") :
size = data.shape[axis_num]
# Number of ticks
nticks = int(np.ceil(np.log2(size)))
nticks += 1 - nticks % 2 # Make <nticks> odd
ticks_position = np.linspace(0, size-1, nticks)
ticks_label = map( lambda x : label_format % x, np.linspace(min_val, max_val, nticks) )
return dict( zip(ticks_position, ticks_label) )
a.axis.xTicks = GetTicks(0, self.x_min, self.x_max)
a.axis.xLabel = "x (rel. units)"
a.axis.yTicks = GetTicks(1, self.y_min, self.y_max)
a.axis.yLabel = "y (rel. units)"
a.axis.zTicks = GetTicks(2, self.z_min, self.z_max)
a.axis.zLabel = "z (rel. units)"
self.fig.Draw()
def __init__ (self, parent, file_name, title="Plot Dirac 3D") :
# Open files
self.f = h5py.File (file_name, 'r')
# Extract the dimension
self.x_gridDIM = int(self.f['x_gridDIM'][...])
self.y_gridDIM = int(self.f['y_gridDIM'][...])
self.z_gridDIM = int(self.f['z_gridDIM'][...])
self.dx = self.f['dx'][...]
self.x_min = self.f['x_min'][...]
self.x_max = self.x_min + self.x_gridDIM * self.dx
self.y_min = self.f['y_min'][...]
self.y_max = self.y_min + self.y_gridDIM * self.dx
self.z_min = self.f['z_min'][...]
self.z_max = self.z_min + self.z_gridDIM * self.dx
# Collect the frame names
self.frame_names = []
for key in self.f.keys () :
try : self.frame_names.append (int(key))
except ValueError: pass
self.frame_names.sort ()
print "\nGet global maximum and minimum..."
# Find the min and max values in all the frames
for frame_number in range(len(self.frame_names)) :
data = self.data_for_plotting (frame_number)
try :
self.global_min = min( self.global_min, data.min() )
self.global_max = max( self.global_max, data.max() )
except AttributeError :
self.global_min = data.min()
self.global_max = data.max()
print "\nStart animation..."
# Create GUI
dw, dh = wx.DisplaySize()
wx.Frame.__init__ (self, parent, title=title, size=(0.4*dw, 0.6*dh) )
self.ConstructGUI ()
self.Center()
self.Show ()
wx.EVT_CLOSE(self, self.on_close)
self.On_animation_button ()
def on_close (self, event) :
try : self.animation_timer.Stop()
except AttributeError : pass
self.Destroy()
def ConstructGUI (self) :
"""
Make a GUI
"""
######################### Navigation bar ##############################
panel = wx.Panel(self)
boxsizer = wx.BoxSizer (wx.HORIZONTAL)
# Frame number indicator
boxsizer.Add (wx.StaticText(panel, label="Frame Number:"))
self.frame_number = wx.SpinCtrl (panel, value="0", min=0, max=len(self.frame_names)-1)
self.frame_number.Bind (wx.EVT_SPINCTRL, self.draw_curent_frame )
boxsizer.Add (self.frame_number)
# Go to the beginning button
self.go_beginnign_button = wx.Button (panel, label="<<")
self.Bind (wx.EVT_BUTTON, self.go_to_beginning, self.go_beginnign_button)
boxsizer.Add (self.go_beginnign_button)
# Animation button
self.animation_button_start_label = "Play animation "
self.animation_button_stop_label = "STOP animation"
self.animation_button = wx.Button (panel, label=self.animation_button_start_label)
self.Bind (wx.EVT_BUTTON, self.On_animation_button, self.animation_button)
boxsizer.Add (self.animation_button)
# Go to the end button
self.go_end_button = wx.Button (panel, label=">>")
self.Bind (wx.EVT_BUTTON, self.go_to_end, self.go_end_button)
boxsizer.Add (self.go_end_button)
panel.SetSizer (boxsizer)
############################# Setting up visvis binding #######################################
Figure = app.GetFigureClass()
self.fig = Figure(self)
################################### Layout #####################################################
sizer = wx.BoxSizer (wx.VERTICAL)
sizer.Add (panel, flag=wx.CENTER)
sizer.Add(self.fig._widget, 1, flag=wx.EXPAND)
self.SetSizer(sizer)
self.SetAutoLayout(True)
self.Layout()
def On_animation_button (self, event=None) :
"""
<self.animation_button> was clicked
"""
if self.animation_button.GetLabel() == self.animation_button_start_label :
# Begin playing animation
# Set up timer for animation
timer_id = wx.NewId ()
self.animation_timer = wx.Timer (self, timer_id)
self.animation_timer.Start (200)
def on_animation_timer (event) :
self.draw_curent_frame()
position = self.frame_number.GetValue()
if position > len(self.frame_names)-2 : self.On_animation_button ()
else : self.frame_number.SetValue (position+1)
wx.EVT_TIMER (self, timer_id, on_animation_timer)
# Channing the button's label
self.animation_button.SetLabel(self.animation_button_stop_label)
else : # Stop playing animation
self.animation_timer.Stop ()
del self.animation_timer
# Channing the button's label
self.animation_button.SetLabel(self.animation_button_start_label)
def go_to_beginning (self, event) :
"""
<self.go_beginnign_button> was clicked
"""
self.frame_number.SetValue (0)
self.draw_curent_frame()
def go_to_end (self, event) :
"""
<self.go_end_button> was clicked
"""
self.frame_number.SetValue (len(self.frame_names)-1)
self.draw_curent_frame()
if __name__ == '__main__' :
import sys
app.Create()
# Loading files
if len(sys.argv) <> 2 :
openFileDialog = wx.FileDialog(None, "Open HDF5 file to load 3D Dirac", "", "",
"HDF5 files (*.hdf5)|*.hdf5", wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_CHANGE_DIR)
# Check whether user canceled
if openFileDialog.ShowModal() == wx.ID_CANCEL:
print "Error: file name is needed as argument"
exit()
else : filename = openFileDialog.GetPath()
else : filename = sys.argv[1]
CPlot3D (None, filename)
app.Run ()
When you call On_animation_button() manually, your frame is not actually shown yet, even though you had called Show() on it because, at least with X11, showing happens asynchronously. So you need to delay calling it until later. This can be done by e.g. binding a lambda doing this to EVT_SIZE event (because by the time you get it, the window is already initialized) or just by using CallAfter().
I am making a form dialog in PyQt5. The objective of the program is to generate numbers according to a particular format depending on the Part type and store these numbers in an Excel sheet. The excel sheet is named 'Master Part Sheet.xlsx' and stored in the same directory as the script. The name of the excel sheet can be changed in the workbookLayer Class. The number of generated numbers is determined by the entry in the number of part numbers required field
The customer selected in the drop down menu also plays a role in generating a part number(only if it is a Machine Part). A number from 0-99 is stored in a dictionary against each customers name which is accessed while generating corresponding part numbers.
The input fields have to be checked when a user enters a value in them. Every time the value entered is incorrect(not in a certain range/ not in the specified format), an exception is called. The values are checked when the generate Qpushbutton in the form dialog is clicked.
The NTID field must be of the form UUUNUUU where U stands for upper case string and N stands for a Number. It is checked for with regular expressions and must otherwise throw exceptions.
The machine number and line number fields must be in the range 0-99, and must otherwise throw an exception prompting the user to check his/her entries in the message label.
After the entry of data by the user and these checks, the part numbers must be generated and written onto the excel sheet.
If the part type is a standard part, the part numbers are written onto the Standard parts sheet of the workbook. The max number of parts that can exist in this sheet are 10000. The part numbers must be unique.
If the sheet is a machine part, new sheets are created in the workbook where the part numbers are written onto. The sheets are created based on the customer name the machine number and the line number. One sheet can have a maximum of 1000 parts and the numbers generated shouldn't be repeated in the sheet i.e they are unique.
Below is the code
'''import all necessary libraries required for the project'''
import os
import numpy as np
import openpyxl
from openpyxl.workbook import Workbook
from openpyxl import load_workbook
import random
import time
import pickle
import re
class workbookLayer:
'''The constructor for the workbook object'''
def __init__(self, source_file='Master Part Sheet.xlsx'): # Change source_file to get different sheet as source
self.source_file = source_file
self.part_type = None
self.line_number = None
self.machine_number = None
self.customer_name = None
self.ntid = None
self.get_sheet_name()
'''Get the path of the Excel workbook and load the workbook onto the object'''
def get_sheet_name(self):
self.file_path = os.path.realpath(self.source_file)
self.wb = load_workbook(self.file_path)
self.wb.get_sheet_names()
return self.file_path, self.wb
from PyQt5.QtWidgets import (QApplication, QComboBox, QDialog,
QDialogButtonBox, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout,
QLabel, QLineEdit, QMenu, QMenuBar, QPushButton, QSpinBox, QTextEdit,
QVBoxLayout, QMessageBox)
import sys
'''The Pop up Box for addition of a new customer'''
class DialogCustomerAdd(QDialog):
NumGridRows = 3
NumButtons = 4
def __init__(self):
super(DialogCustomerAdd, self).__init__()
self.createFormGroupBox()
self.ok_button=QPushButton("OK")
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.formGroupBox)
mainLayout.addWidget(self.ok_button)
self.ok_button.clicked.connect(self.ok_button_action)
self.setLayout(mainLayout)
self.setWindowTitle("Add New Customer")
def ok_button_action(self):
global CUSTOMER_NAME
global CUSTOMER_ID
CUSTOMER_NAME = self.customer_name_text.text()
CUSTOMER_ID = self.customer_id_text.text()
self.close()
def createFormGroupBox(self):
self.formGroupBox = QGroupBox("Customer Details")
layout = QFormLayout()
self.customer_name_label = QLabel("Name of the Customer")
self.customer_name_text = QLineEdit()
self.customer_id_label = QLabel("Enter Customer ID")
self.customer_id_text = QLineEdit()
layout.addRow(self.customer_name_label, self.customer_name_text)
layout.addRow(self.customer_id_label, self.customer_id_text)
self.formGroupBox.setLayout(layout)
'''The Pop up Box for deletion of an existing customer'''
class DialogCustomerDelete(QDialog):
NumGridRows = 3
NumButtons = 4
def __init__(self):
super(DialogCustomerDelete, self).__init__()
self.createFormGroupBox()
self.ok_button=QPushButton("OK")
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.formGroupBox)
mainLayout.addWidget(self.ok_button)
self.ok_button.clicked.connect(self.ok_button_action)
self.setLayout(mainLayout)
self.setWindowTitle("Delete Existing Customer")
def ok_button_action(self):
global POP_CUSTOMER
POP_CUSTOMER = self.customer_delete_combobox.currentText()
self.customer_delete_combobox.clear()
self.close()
def createFormGroupBox(self):
self.formGroupBox = QGroupBox("Customer Details")
layout = QFormLayout()
self.customer_name_label = QLabel(" Select the Customer to be deleted")
self.customer_delete_combobox = QComboBox()
self.customer_delete_combobox.addItems(CUSTOMER_LIST)
layout.addRow(self.customer_name_label)
layout.addRow(self.customer_delete_combobox)
self.formGroupBox.setLayout(layout)
class DialogMain(QDialog):
NumGridRows = 3
NumButtons = 4
wbl = workbookLayer()
def __init__(self):
super(DialogMain, self).__init__()
self.createFormGroupBox()
generate_button=QPushButton("Generate")
generate_button.clicked.connect(self.generateNumbers)
self.user_message_label = QLabel(" ")
buttonBox = QDialogButtonBox(QDialogButtonBox.Cancel)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.formGroupBox)
mainLayout.addWidget(self.user_message_label)
mainLayout.addWidget(generate_button)
mainLayout.addWidget(self.add_new_customer_button)
mainLayout.addWidget(self.delete_customer_button)
buttonBox.clicked.connect(self.closeIt)
mainLayout.addWidget(buttonBox)
self.setLayout(mainLayout)
self.open_or_create_pickle_file()
customer_name = [customer for customer,customer_id in self.customer_dict.items()]
self.customer_name_combobox.addItems(customer_name)
self.add_new_customer_button.clicked.connect(self.add_customer_window)
self.delete_customer_button.clicked.connect(self.delete_customer_window)
self.setWindowTitle("Part Number Generator ")
global CUSTOMER_LIST
CUSTOMER_LIST = customer_name
def open_or_create_pickle_file(self):
self.customer_dict = dict()
try:
assert open("customer_diction.pickle","rb")
pickle_in = open("customer_diction.pickle","rb")
self.customer_dict = pickle.load(pickle_in)
pickle_in.close()
except FileNotFoundError:
pickle_out = open("customer_dict.pickle","wb")
def add_new_customer_to_pickle(self):
global CUSTOMER_NAME
global CUSTOMER_ID
global CUSTOMER_LIST
self.customer_name_combobox.addItem(CUSTOMER_NAME)
self.customer_dict[CUSTOMER_NAME] = CUSTOMER_ID
customer_name = [customer for customer,customer_id in self.customer_dict.items()]
CUSTOMER_LIST = customer_name
pickle_out = open("customer_diction.pickle","wb")
pickle.dump(self.customer_dict, pickle_out)
pickle_out.close()
def delete_customer_from_pickle(self):
global POP_CUSTOMER
del self.customer_dict[POP_CUSTOMER]
customer_name = [customer for customer,customer_id in self.customer_dict.items()]
global CUSTOMER_LIST
CUSTOMER_LIST = customer_name
self.customer_name_combobox.clear()
self.customer_name_combobox.addItems(customer_name)
pickle_out = open("customer_diction.pickle","wb")
pickle.dump(self.customer_dict, pickle_out)
pickle_out.close()
def add_customer_window(self):
widget = DialogCustomerAdd()
widget.exec_()
self.add_new_customer_to_pickle()
def delete_customer_window(self):
widget = DialogCustomerDelete()
widget.exec_()
self.delete_customer_from_pickle()
global POP_CUSTOMER
self.user_message_label.setText('The customer ' + POP_CUSTOMER + ' has been deleted' )
def closeIt(self):
self.close()
def generateNumbers(self):
self.wbl.line_number = self.line_number_text.text()
self.wbl.machine_number = self.machine_number_text.text()
self.wbl.customer_name =self.customer_name_combobox.currentText()
self.wbl.part_type = self.part_type_combobox.currentText()
self.wbl.ntid = self.ntid_text.text()
try:
self.check_ntid()
except AssertionError:
self.user_message_label.setText('Please Enter User Details Correctly')
try:
if int(self.wbl.machine_number) > 99:
raise ValueError
except ValueError:
self.user_message_label.setText('Please Enter machine number within 100')
try:
if int(self.wbl.line_number) > 99:
raise ValueError
except ValueError:
self.user_message_label.setText('Please Enter Line number within 100')
self.create_sheet_and_check_values()
try:
self.part_number_generator()
except PermissionError:
self.user_message_label.setText('Please Close the excel sheet before using this application')
def createFormGroupBox(self):
self.formGroupBox = QGroupBox("Part Details")
layout = QFormLayout()
self.part_type_label = QLabel("Part Type:")
self.part_type_combobox = QComboBox()
self.part_type_combobox.addItems(['Standard Part', 'Machine Part'])
self.customer_name_label = QLabel("Customer:")
self.customer_name_combobox = QComboBox()
self.add_new_customer_button = QPushButton("Add New Customer")
self.delete_customer_button = QPushButton("Delete Existing Customer")
self.ntid_label = QLabel("NTID of the User:")
self.ntid_text = QLineEdit()
self.machine_number_label = QLabel("Machine Number of the Part:")
self.machine_number_text = QLineEdit()
self.line_number_label = QLabel("Line Number of the Part:")
self.line_number_text = QLineEdit()
self.part_numbers_label = QLabel("Number of Part Numbers Required:")
self.part_numbers_spinbox = QSpinBox()
self.part_numbers_spinbox.setRange(1, 999)
layout.addRow(self.part_type_label, self.part_type_combobox)
layout.addRow(self.customer_name_label, self.customer_name_combobox)
layout.addRow(self.ntid_label, self.ntid_text)
layout.addRow(self.machine_number_label, self.machine_number_text)
layout.addRow(self.line_number_label, self.line_number_text)
layout.addRow(self.part_numbers_label, self.part_numbers_spinbox)
self.formGroupBox.setLayout(layout)
def check_ntid(self):
pattern = re.compile("^[A-Z][A-Z][A-Z][0-9][A-Z][A-Z][A-Z]")
assert pattern.match(self.wbl.ntid)
def create_sheet_and_check_values(self):
self.check_ntid()
if self.wbl.part_type == 'Machine Part':
self.prefix = int('3' + self.customer_dict[self.wbl.customer_name] + self.wbl.line_number + self.wbl.machine_number)
self.check_and_create_customer_sheet()
else:
self.prefix = 500000
self.add_standard_parts_sheet()
self.dest_filename = self.wbl.file_path
self.ws1 = self.wbl.wb[self.wbl.sheet_name]
self.random_numbers = self.part_numbers_spinbox.value()
if (self.wbl.part_type == 'Machine Part'):
try:
assert self.random_numbers < (1002 -(self.ws1.max_row))
except AssertionError:
self.user_message_label.setText('You have exceeded the range of allowable parts in the machine, you can get only {} more part numbers'.format(1001 -(self.ws1.max_row)))
else:
try:
assert self.random_numbers < (10002 -(self.ws1.max_row))
except AssertionError:
self.user_message_label.setText('You have exceeded the range of allowable parts in this list, you can get only {} more part numbers'.format(10001 -(self.ws1.max_row)))
'''This section of the method contains the logic for the generation of random number parts
according to the required format and also checks for clashes with already existing part numbers'''
def part_number_generator(self):
if (self.wbl.part_type == 'Machine Part'):
part_numbers_list = random.sample(range( self.prefix*1000, self.prefix*1000 + 1000), self.random_numbers)
else:
part_numbers_list = random.sample(range( self.prefix*10000, self.prefix*10000 + 10000), self.random_numbers)
first_column = set([(self.ws1[x][0].value) for x in range(2,self.ws1.max_row + 1 )])
while True:
additional_part_numbers_list = random.sample(range( self.prefix*1000, self.prefix*1000 + 1000), self.random_numbers - len (part_numbers_list))
part_numbers_list = part_numbers_list + additional_part_numbers_list
part_numbers_list = list(set(part_numbers_list) - (first_column))
if len(part_numbers_list) == self.random_numbers:
break
for row in range( self.ws1.max_row + 1, self.ws1.max_row + 1 + len(part_numbers_list)):
'''write the generated part numbers onto the excel sheet corresponding to the customer'''
self.ws1.cell(column = 1 , row = row, value = part_numbers_list.pop())
self.ws1.cell(column = 3 , row = row, value = self.wbl.ntid)
self.wbl.wb.save(self.wbl.file_path)
self.user_message_label.setText(str(self.part_numbers_spinbox.value()) + " Part Numbers have been successfully generated. Please check the sheet " + self.wbl.sheet_name)
def check_and_create_customer_sheet(self):
self.wbl.sheet_name = '3' + self.customer_dict[self.wbl.customer_name] + self.wbl.line_number + self.wbl.machine_number +'xxx'
if self.customer_not_exists():
self.wbl.wb.create_sheet(self.wbl.sheet_name)
self.wbl.wb.save(self.wbl.file_path)
'''Check if the customer sheet exists'''
def customer_not_exists(self):
sheet_name = '<Worksheet "'+ '3' + self.customer_dict[self.wbl.customer_name] + self.wbl.line_number + self.wbl.machine_number +'xxx' + '">'
return True if sheet_name not in str(list(self.wbl.wb)) else False
'''Check if standard parts sheet exists. If not make a new sheet'''
def add_standard_parts_sheet(self):
sheet_name = '<Worksheet "'+ 'Standard Parts'+ '">'
if sheet_name not in str(list(self.wbl.wb)):
self.wbl.wb.create_sheet('Standard Parts')
self.wbl.wb.save(self.wbl.file_path)
self.wbl.sheet_name = 'Standard Parts'
if __name__ == '__main__':
app = QApplication(sys.argv)
dialog = DialogMain()
sys.exit(dialog.exec_())
The generateNumbers() function in the DialogMain() Class is called every time a 'generate' QpushButton is clicked in the QDialog layout. The program checks for correctness of the inputs and generates random numbers according to the required format in an excel sheet through openpyxl. The exceptions for the self.wbl.ntid and PermissionError work as expected. However the exceptions for self.wbl.machine_number and self.wb1.line_number i.e for machine number inputs and line number inputs in the dialog seem to be ignored and the program executes even when the user entry is wrong. Only the exception for NTID behaves as expected and the other exceptions fail to be raised even on wrong entry.
The dialog Box
I have added the entire code used to make it reproducible. Thanks
I am trying to generate a bunch of variables from a list, which will be called from another function.
If I create them separately(as in the commented part of the code), everything is working fine(by fine, I mean, I can access the date using get_data function listed below). But, when I am using the loop, the get_data is giving error:
File "main.py", line 97, in get_data
dAu = self.Author.get_text()
AttributeError: 'MyWindow' object has no attribute 'Author'
So, it is obvious that inside the loop, EDITI am expecting, for field[0],
self.field = self.field[0]=self.Author
but this is not the case.EDIT COMPLETE
self.field != self.Author
as I wished.
How can I get that?
The code in question is:
# Generate the Entry fields
self.notebook = Gtk.Notebook()
# self.LAuthor = Gtk.Label("Author")
# self.EAuthor = Gtk.Entry()
# self.page = Gtk.Grid()
# self.page.attach(self.LAuthor, 0, 0, 2, 1)
# self.page.attach_next_to(self.EAuthor, self.LAuthor, Gtk.PositionType.RIGHT, 1, 1)
# self.notebook.append_page(self.page, Gtk.Label("Trial"))
xpos = 0
minf = 0
fields = ["Author", "Year", "Journal", "Title", "Publisher", "Page",
"Address", "Annote", " Booktitle", "Chapter", "Crossred",
"Edition", "Editor", "HowPublished", "Institution", "Month",
"Note", "Number", "Organization", "Pages", "Publishers",
"School", "Series", "Type"]
Tabs = ["Essential", "Publishers", "Extra I", "Extra II"]
for note in range(int(len(fields)/6)):
ypos = 0
self.npage = "page"+str(note)
self.npage = Gtk.Grid()
self.npage.set_border_width(10)
maxf = minf+6
for field in fields[minf:maxf]:
print(field)
self.lfield = "L" + field
self.lfield = Gtk.Label(field)
self.field = Gtk.Entry()
self.field.set_placeholder_text(field)
self.npage.attach(self.lfield, xpos, ypos, 2, 1)
self.npage.attach_next_to(self.field, self.lfield,
Gtk.PositionType.RIGHT, 1, 1)
ypos += 1
self.notebook.append_page(self.npage, Gtk.Label(Tabs[note]))
minf = maxf
And the get_data function is just:
def get_data(self, widget):
dAu = self.Author.get_text()
print(dAu)
Kindly help.
Use dictionary - for example:
self.all_fields = dict()
field = "Author"
self.all_fields[field] = ...
# self.all_fields["Author"] = ...
and then you can use
def get_data(self, widget):
dAu = self.all_fields["Author"].get_text()
print(dAu)