I'm making an application in python that can access an excel file to read and write data. Excel file has weekdays and user will be reading or writing the cell next to them. Below, I wrote some loops to check if user left some changes unsaved. And if the cell for a certain day has unsaved changes, label inside the app changes to point it out to the user.
Like: Monday --> Monday*
"kvlabel", for some reason stays in a darker color and hovering my mouse over it reveals that it's not accessed by Pylance. I changed it's name and position but it doesn't make a difference.
daytexts = [
self.root.get_screen("weeklywin").ids.mon_text.text,
self.root.get_screen("weeklywin").ids.tue_text.text,
self.root.get_screen("weeklywin").ids.wed_text.text,
self.root.get_screen("weeklywin").ids.thu_text.text,
self.root.get_screen("weeklywin").ids.fri_text.text
]
cells = [e4, e10, e16, e22, e28]
daylabel = ["mon_label", "tue_label", "wed_label", "thu_label", "fri_label"]
daylabelkv = [
self.root.get_screen("weeklywin").ids.mon_label.text,
self.root.get_screen("weeklywin").ids.tue_label.text,
self.root.get_screen("weeklywin").ids.wed_label.text,
self.root.get_screen("weeklywin").ids.thu_label.text,
self.root.get_screen("weeklywin").ids.fri_label.text
]
justday = ["Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma"]
for day, cell, label in zip(daytexts, cells, daylabel):
if day != cell and label not in self.excel_unsaved_label:
self.excel_unsaved_label.append(label)
elif day == cell and label in self.excel_unsaved_label:
self.excel_unsaved_label.remove(label)
if self.excel_unsaved_label:
self.show_excel_leave_warn()
for label2, kvlabel, tehday in zip(daylabel, daylabelkv, justday):
if label2 in self.excel_unsaved_label:
kvlabel = tehday+"*"
else:
kvlabel = tehday
else:
self.root.current = caller
Like #slothrop suggested, I removed .text from daylabelkv:
daylabelkv = [
self.root.get_screen("weeklywin").ids.mon_label,
self.root.get_screen("weeklywin").ids.tue_label,
self.root.get_screen("weeklywin").ids.wed_label,
self.root.get_screen("weeklywin").ids.thu_label,
self.root.get_screen("weeklywin").ids.fri_label]
and changed the loop like this:
for label2, i, tehday in zip(daylabel, range(len(daylabelkv)), justday):
if label2 in self.excel_unsaved_label:
daylabelkv[i].text = tehday+"*"
It does what I want now. Thank you all for your help.
Related
I'm trying to see if there's a way to type a number between 1 and 4 into an entry box, then go to the next entry box (with the number entered into the box; the code below skips to the next entry without entering anything)
I'm creating a program that will take item-level data entry to be computed into different subscales. I have that part working in different code, but would prefer not to have to hit tab in between each text entry box since there will be a lot of them.
Basic code:
from tkinter import *
master = Tk()
root_menu = Menu(master)
master.config(menu = root_menu)
def nextentrybox(event):
event.widget.tk_focusNext().focus()
return('break')
Label(master, text='Q1',font=("Arial",8)).grid(row=0,column=0,sticky=E)
Q1=Entry(master, textvariable=StringVar)
Q1.grid(row=0,column=1)
Q1.bind('1',nextentrybox)
Q1.bind('2',nextentrybox)
Q1.bind('3',nextentrybox)
Q1.bind('4',nextentrybox)
Label(master, text='Q2',font=("Arial",8)).grid(row=1,column=0,sticky=E)
Q2=Entry(master, textvariable=StringVar)
Q2.grid(row=1,column=1)
Q2.bind('1',nextentrybox)
Q2.bind('2',nextentrybox)
Q2.bind('3',nextentrybox)
Q2.bind('4',nextentrybox)
### etc for rest of questions
### Scale sums, t-score lookups, and report generator to go here
file_menu = Menu(root_menu)
root_menu.add_cascade(label = "File", menu = file_menu)
file_menu.add_separator()
file_menu.add_command(label = "Quit", command = master.destroy)
mainloop()
Thanks for any help or pointers!
The simplest solution is to enter the event keysym before proceeding to the next field.
In the following example, notice how I added a call to event.widget.insert before moving the focus:
def nextentrybox(event):
event.widget.insert("end", event.keysym)
event.widget.tk_focusNext().focus()
return('break')
this is a part of my code.
class AboutRelatedDialog(wx.Dialog):
def __init__(self,parent,list1,list2,list3):
wx.Dialog.__init__(self,parent,-1)
RelatedGrid = gridlib.Grid(self)
RelatedGrid.CreateGrid(sum(list2) + 1,5)
RelatedGrid.SetColLabelSize(1)
RelatedGrid.SetRowLabelSize(1)
RelatedGrid.SetCellSize(0,0,1,2)
RelatedGrid.SetCellAlignment(0,0,wx.ALIGN_CENTRE,wx.ALIGN_CENTRE)
RelatedGrid.SetCellValue(0,0,'label')
RelatedGrid.SetCellAlignment(0,2,wx.ALIGN_CENTRE,wx.ALIGN_CENTRE)
RelatedGrid.SetCellValue(0,2,'datasource')
RelatedGrid.SetCellAlignment(0,3,wx.ALIGN_CENTRE,wx.ALIGN_CENTRE)
RelatedGrid.SetCellValue(0,3,'data')
RelatedGrid.SetCellAlignment(0,4,wx.ALIGN_CENTRE,wx.ALIGN_CENTRE)
RelatedGrid.SetCellValue(0,4,'comment')
templist1 = ms.ExecQuery('SELECT RepGroup FROM RepGroup')
templist2 = []
for i in templist1:
j = i[0]
templist2.append(j)
for index in range(len(list3)):
RelatedGrid.SetCellAlignment(index + 1,1,wx.ALIGN_CENTRE,wx.ALIGN_CENTRE)
RelatedGrid.SetCellValue(index + 1,1,list3[index])
for i in range(sum(list2) + 1):
dbsource = gridlib.GridCellChoiceEditor(templist2)
RelatedGrid.SetCellEditor(i,2,dbsource)
#RelatedGrid.Bind(wx.EVT_CHOICE,self.EvtChoice,dbsource)
def EvtChoice(self,event):
print 1
and my code doesn't work,because i don't know how to bind a event for these combobox.
when i choose a datasource,i want to create another combobox to show the data that get from the RepGroup table in another cell.
so i must know how to get the event when i choose a datasoure.
You can't (easily) bind to the events generated by wxGrid editor controls, but you can handle EVT_GRID_CELL_CHANGED events generated by the grid itself whenever a value of one of its cells changes.
I'm trying to generate multiple ComboBoxes with values from a "config.ini" file, the config.ini file data is:
priority1 = Normal:farty-blobble-fx.wav:2
priority8 = Reclamacao:buzzy-blop.wav:3
priority3 = Critico:farty-blobble-fx.wav:5
priority2 = Urgente:echo-blip-thing.wav:4
and the goal is turning the sound files names to the select values in the comboboxes.
My code to generate the comboboxes is:
content_data = []
for name, value in parser.items(section_name):
if name=="name":
self.note.add(self.tab2, text = value)
else:
data_prior = value.split(":")
self.PRIOR_LABEL = Label(self.tab2, text=data_prior[0])
self.PRIOR_LABEL.grid(row=data_prior[2],column=0,pady=(10, 2),padx=(40,0))
self.PRIOR_SOUNDS = None
self.PRIOR_SOUNDS = None
self.box_value = StringVar()
self.PRIOR_SOUNDS = Combobox(self.tab2, textvariable=self.box_value,state='readonly',width=35)
self.PRIOR_SOUNDS['values'] = getSoundsName()
self.PRIOR_SOUNDS.current(int(getSoundsName().index(data_prior[1])))
self.PRIOR_SOUNDS.grid(row=data_prior[2],column=1,pady=(10, 2),padx=(30,0))
self.PLAY = Button(self.tab2)
self.PLAY["width"] = 5
self.PLAY["text"] = "Play"
self.PLAY["command"] = lambda:playSound(self.PRIOR_SOUNDS.get())
self.PLAY.grid(row=data_prior[2], column=3,pady=(10,2),padx=(5,0))
And i was unable to show the current values of the "config.ini" file in the comboboxes.
Thank you in advance.
The problem is that you're creating more than one combobox, yet you keep overwriting the variables in each iteration of the loop. At the end of the loop, self.PRIOR_SOUNDS will always point to the last combobox that you created. The same is true for self.box_value, self.PLAY, etc.
The simplest solution is to use an array or dictionary to store all of your variables. A dictionary lets you reference each widget or variable by name; using a list lets you reference them by their ordinal position.
A solution using a dictionary would look something like this:
self.combo_var = {}
self.combo = {}
for name, value in parser.items(section_name):
...
self.combo_var[name] = StringVar()
self.combo[name] = Combobox(..., textvariable = self.combo_var[name])
...
guys.I'm working on a GUI for controlling some robots.
There is a table which shows the current states data about that robot.And the table is updated periodically from the data in the test server.When the updating was not connected it was easy to select a row in the table and save the selected row's data.However,when the server is connected, it becomes impossible to select a row(when u click on the row,the selected row will be highlighted only in a flash and gone).I try to use some print method to see what has happened inside, it seems that the slots will not be implemented when the updating is running.And the updating will also deselect the row frequently.I'm considering block the updating when I manually select a row,then automatically select the same row with a piece of logic and the selectRow() method.Do u have any suggestion for how to block the updating or another way to deal with this problem?
1.updating method, which work as a slot in a Gui Controller class to manage input
def tbRobotChanged(self, currentCell):
# get the selected cell's index from currentCell,Implement the Slot method
tablemodel= currentCell.model()
#get the model of the currentcell
firstColumn = tablemodel.index(currentCell.row(),0)
#change it to the first column in the row with the robot name
self.statusBar().showMessage("Selected Robot is " +
firstColumn.data().toString())
self.selected_robot = int(firstColumn.data().toString())
# show the selected robot name in the statusbar
2.table definition ,this is part of a Gui class which define the main window:
def initRobotsFrame(self, rf):
hbox = QtGui.QHBoxLayout()
self.robot_table = QtGui.QTableView()
self.table_header = ['Robot', 'PosX', 'PosY', 'Heading']
tm = RobotTableModel([[0, 0, 0, 2],[1, 1,2,4]],
self.table_header)
self.robot_table.setModel(tm)
vh = self.robot_table.verticalHeader()
vh.setVisible(False)
self.robot_table.resizeColumnsToContents()
self.robot_table.setSizePolicy(QtGui.QSizePolicy(
QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Minimum))
hbox.addWidget(self.robot_table)
self.selected_robot = 0
block_true=GUIController.robot_data.blockSignals(True)
GUIController.robot_data.blockSignals(block_true)
# select table by row instead of by cell:
self.robot_table.setSelectionBehavior(
QtGui.QAbstractItemView.SelectRows)
# set the signal and slot using selectionModel:
self.robot_table.selectionModel().currentRowChanged.connect(
self.tbRobotChanged)
self.robot_table.selectionModel().currentRowChanged.connect(
self.updateActiveRobot)
# implement a statusbar to test the table selection functionality:
self.statusBar().showMessage("Ready")
rf.setLayout(hbox)
3.slot to get the selected row's data:
def tbRobotChanged(self, currentCell):
# get the selected cell's index from currentCell,Implement the Slot method
tablemodel= currentCell.model()
#get the model of the currentcell
firstColumn = tablemodel.index(currentCell.row(),0)
#change it to the first column in the row with the robot name
self.statusBar().showMessage("Selected Robot is " +
firstColumn.data().toString())
self.selected_robot = int(firstColumn.data().toString())
# show the selected robot name in the statusbar
I am writing a converter code for our Data Department to convert fixed width files into delmited files. Normally we use import the file into Excel, use the text import wizard to set the field lengths, and then just save as a csv. However we have run into the limitation where we have started getting files that are millions of records long, and thus cant be imported into Excel. The files do not always have spaces in between the fields, espicially so between value fields like phone numbers or zip codes. The headers are also often filled completely in with no spaces.
A sample of a typical fixed width file we are dealing with:
SequenSack and PaFull Name****************************]JOB TITLE****************]HOSP NAME******************************]Delivery Address***********************]Alternate 1 Address********************]Calculated Text**********************************]POSTNET Bar
000001T1 P1 Sample A Sample 123 Any Street Anytown 12345-6789 12345678900
000002T1 P1 Sample A Sample Director of Medicine 123 Any Street Po Box 1234 Anytown 12345-6789 12345678900
The program needs to break file into the following delimited fields:
Sequen
Sack and Pa
Full name
Job Title
Hosp Name
Delivery Address
Alternate Address 1
Calculated Text
POSTNET Bar
Each file as a slightly different width of each field depending on the rest of the job. What i am looking for is a GUI oriented delimiter much like the Excel import wizard for fixed width files. I am writing this tool in Python as a part of a larger tool that does many other file operations such as breaking up files into multiple up, reversing a file, converting from delimited to fixed width and check digit checking. I am using Tkinter for the rest of the tools and it would be ideal if the solution use it as well.
Any help appreciated
If I understand the problem correctly (and there's a good chance I don't...), the simplest solution might be to use a text widget.
Make the first line be a series of spaces the same length as the row. Use a couple of alternating tags (eg: "even" and "odd") to give each character an alternate color so they stand out from one another. The second line would be the header, and any remaining lines would be a couple lines of sample data.
Then, set up bindings on the first row to convert a space into an "x" when the user clicks on a character. If they click on an "x", convert it back to a space. They can then go and click on the character that is the start of each column. When the user is done, you can get the first line of the text widget and it will have an "x" for each column. You then just need a little function that translates that into whatever format you need.
It would look roughly like this (though obviously the colors would be different than what appears on this website)
x x x ...
SequenSack and PaFull Name****************************]JOB...
000001T1 P1 Sample A Sample ...
Here's a quick hack to illustrate the general idea. It's a little sloppy but I think it illustrates the technique. When you run it, click on an area in the first row to set or clear a marker. This will cause the header to be highlighted in alternate colors for each marker.
import sys
import Tkinter as tk
import tkFont
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
header = "SequenSack and PaFull Name****************************]JOB TITLE****************]HOSP NAME******************************]Delivery Address***********************]Alternate 1 Address********************]Calculated Text**********************************]POSTNET Bar"
sample = "000001T1 P1 Sample A Sample 123 Any Street Anytown 12345-6789 12345678900"
widget = DelimiterWidget(self, header, sample)
hsb = tk.Scrollbar(orient="horizontal", command=widget.xview)
widget.configure(xscrollcommand=hsb.set)
hsb.pack(side="bottom", fill="x")
widget.pack(side="top", fill="x")
class DelimiterWidget(tk.Text):
def __init__(self, parent, header, samplerow):
fixedFont = tkFont.nametofont("TkFixedFont")
tk.Text.__init__(self, parent, wrap="none", height=3, font=fixedFont)
self.configure(cursor="left_ptr")
self.tag_configure("header", background="gray")
self.tag_configure("even", background="#ffffff")
self.tag_configure("header_even", background="bisque")
self.tag_configure("header_odd", background="lightblue")
self.tag_configure("odd", background="#eeeeee")
markers = " "*len(header)
for i in range(len(header)):
tag = "even" if i%2==0 else "odd"
self.insert("end", " ", (tag,))
self.insert("end", "\n")
self.insert("end", header+"\n", "header")
self.insert("end", samplerow, "sample")
self.configure(state="disabled")
self.bind("<1>", self.on_click)
self.bind("<Double-1>", self.on_click)
self.bind("<Triple-1>", self.on_click)
def on_click(self, event):
'''Handle a click on a marker'''
index = self.index("#%s,%s" % (event.x, event.y))
current = self.get(index)
self.configure(state="normal")
self.delete(index)
(line, column) = index.split(".")
tag = "even" if int(column)%2 == 0 else "odd"
char = " " if current == "x" else "x"
self.insert(index, char, tag)
self.configure(state="disabled")
self.highlight_header()
return "break"
def highlight_header(self):
'''Highlight the header based on marker positions'''
self.tag_remove("header_even", 1.0, "end")
self.tag_remove("header_odd", 1.0, "end")
markers = self.get(1.0, "1.0 lineend")
i = 0
start = "2.0"
tag = "header_even"
while True:
try:
i = markers.index("x", i+1)
end = "2.%s" % i
self.tag_add(tag, start, end)
start = self.index(end)
tag = "header_even" if tag == "header_odd" else "header_odd"
except ValueError:
break
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
edit: I now see that you are looking for a gui. I'll leave this incorrect answer for posterity.
import csv
def fixedwidth2csv(fw_name, csv_name, field_info, headings=None):
with open(fw_name, 'r') as fw_in:
with open(csv_name, 'rb') as csv_out: # 'rb' => 'r' for python 3
wtr = csv.writer(csv_out)
if headings:
wtr.writerow(headings)
for line in fw_in:
wtr.writerow(line[pos:pos+width].strip() for pos, width in field_info)