Related
I'm getting the error "UnboundLocalError: local variable 'qn' referenced before assignment" on running the code. Why is that? How can I correct it? I'm new to tkinter so please try to keep it simple. This is part of the code for a game I was writing. It would be a great help if I could get an answer soon
from tkinter import *
from tkinter import messagebox
from io import StringIO
root = Tk()
root.title("Captain!")
root.geometry("660x560")
qn = '''1$who are you?$char1$i am joe$3$i am ben$2
2$what are you?$char2$i am a person$1$i am nobody$3
3$how are you?$char3$i am fine$2$i'm alright$1'''
var = '''1$10$-35$20$15$-20
2$9$7$30$-5$-15
3$10$-25$-15$10$5'''
class Game :
def __init__(self):
self.m_cur = {1:["Military",50]}
self.c_cur = {1:["People's",50]}
self.r_cur = {1:["Research",50]}
self.i_cur = {1:["Industrial",50]}
self.p_cur = {1:["Research",50]}
#function to clear all widgets on screen when called
def clear(self):
for widget in root.winfo_children():
widget.destroy()
#function to quit the window
def exit(self):
msg = messagebox.askquestion("Thank you for playing","Are you sure you want to exit?")
if msg == "yes" :
root.destroy()
else:
Game.main(self)
#start function
def start(self):
Label(root,text="Hello, what should we call you?",font=("segoe print",20)).grid(row=0,column=0)
name = Entry(root,width=20)
name.grid(row=1,column=0)
Button(root,text="Enter",font=("segoe print",20),command=lambda: Game.main(self)).grid(row=1,column=1)
self.name=name.get()
#main function
def main(self):
Game.clear(self)
Label(root,text="Welcome to the game",font=("segoe print",20)).grid(row=0,column=0)
Label(root,text='What do you want to do?',font=("segoe print",20)).grid(row=1,column=0)
Button(root,text="Start Game",font=("segoe print",20),command=lambda: Game.qn_func(self,1)).grid(row=2,column=0)
Button(root,text="Exit Game",font=("segoe print",20),command=lambda: Game.exit(self)).grid(row=3,column=0)
#function to check variables and display game over
def game_over(self,x_cur):
if x_cur[1][1]<=0 or x_cur[1][1]>=100 : #condition to check game over
Game.clear(self)
Label(root,text=x_cur)
Label(root,text="GAME OVER",font=("ariel",20)).place(relx=0.5,rely=0.5,anchor=CENTER)
Button(root,text="Continue",font=("segoe print",20),command=lambda: Game.main(self)).place(relx=0.5,rely=0.6)
#function to display question and variables
def qn_func(self,qn_num) :
Game.clear(self)
#accessing the questions
q_file = StringIO(qn)
#reading the question, options, next qn numbers and the character name from the file
qn_list = q_file.readlines()
qn = qn_list[qn_num-1].strip().split("$")[1]
char_name = qn_list[qn_num-1].strip().split("$")[2]
qn1 = qn_list[qn_num-1].strip().split("$")[3]
qn2 = qn_list[qn_num-1].strip().split("$")[5]
n_qn1 = int(qn_list[qn_num-1].strip().split("$")[4])
n_qn2 = int(qn_list[qn_num-1].strip().split("$")[6])
#displaying the character name and the question as a label frame widget with character name as parent
label_frame = LabelFrame(root,text = char_name,font = ("segoe print",20))
label = Label(label_frame,text = qn,font = ("segoe print",20))
label_frame.place(relx=0.5,rely=0.5,anchor=CENTER)
label.pack()
q_file.close()
#accessing variables
v_file = StringIO(var)
#reading values of variables from file
v_list = v_file.readlines()
self.r_cur[1][1] += int(v_list[qn_num-1].strip().split("$")[1])
self.c_cur[1][1] += int(v_list[qn_num-1].strip().split("$")[2])
self.i_cur[1][1] += int(v_list[qn_num-1].strip().split("$")[3])
self.m_cur[1][1] += int(v_list[qn_num-1].strip().split("$")[4])
self.p_cur[1][1] += int(v_list[qn_num-1].strip().split("$")[5])
#running each variable through game_over to see if you are dead
Game.game_over(self,self.r_cur)
Game.game_over(self,self.c_cur)
Game.game_over(self,self.i_cur)
Game.game_over(self,self.m_cur)
Game.game_over(self,self.p_cur)
#defining the Doublevar variables
s_var1 = DoubleVar()
s_var2 = DoubleVar()
s_var3 = DoubleVar()
s_var4 = DoubleVar()
s_var5 = DoubleVar()
#setting the values in the scales
s_var1.set(self.r_cur[1][1])
s_var2.set(self.c_cur[1][1])
s_var3.set(self.i_cur[1][1])
s_var4.set(self.m_cur[1][1])
s_var5.set(self.p_cur[1][1])
#variables as scale widgets
scale1 = Scale(root,from_=100,to=0,orient=VERTICAL,sliderlength=10,variable=s_var1)
scale2 = Scale(root,from_=100,to=0,orient=VERTICAL,sliderlength=10,variable=s_var2)
scale3 = Scale(root,from_=100,to=0,orient=VERTICAL,sliderlength=10,variable=s_var3)
scale4 = Scale(root,from_=100,to=0,orient=VERTICAL,sliderlength=10,variable=s_var4)
scale5 = Scale(root,from_=100,to=0,orient=VERTICAL,sliderlength=10,variable=s_var5)
#displaying the scale widgets on the screen
scale1.grid(row=0,column=0)
scale2.grid(row=0,column=1)
scale3.grid(row=0,column=2)
scale4.grid(row=0,column=3)
scale5.grid(row=0,column=4)
#disabling the scales
scale1.config(state=DISABLED)
scale2.config(state=DISABLED)
scale3.config(state=DISABLED)
scale4.config(state=DISABLED)
scale5.config(state=DISABLED)
v_file.close()
#displaying the buttons on the screen
Button(root,text=qn1,command=lambda: Game.qn_func(self,n_qn1)).place(relx=0.2,rely=0.7,anchor=W,width=200,height=50)
Button(root,text=qn2,command=lambda: Game.qn_func(self,n_qn2)).place(relx=0.8,rely=0.7,anchor=E,width=200,height=50)
game = Game()
game.start()
root.mainloop()
You can see in this particular section that you have called on 'qn' before it was even defined:
#function to display question and variables
def qn_func(self,qn_num) :
Game.clear(self)
#accessing the questions
q_file = StringIO(qn)
#reading the question, options, next qn numbers and the character name from the file
qn_list = q_file.readlines()
qn = qn_list[qn_num-1].strip().split("$")[1]
The variable needs to be assigned a value before being used. Here, you call q_file = StringIO(qn) before you have defined qn = qn_list....
I'm creating a simple calculation program using tkinter module and want to convert to exe as I want it to be executable at any pc. But somehow the error message show (failed to execute script pyi_rth_win32comgenpy).
I've try used pyinstaller ( cmd and the one on GitHub at : https://github.com/brentvollebregt/auto-py-to-exe) but to no avail. I also try using both types of python file (.py and .pyw)
from tkinter import *
from tkinter.filedialog import askopenfilename
import pandas as pd
from tkinter import messagebox
from pandastable import Table, TableModel
class Window(Frame):
def __init__(self, master =None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.master.title('GUI')
self.pack(fill=BOTH, expand=1)
quitButton = Button(self, text='quit', command=self.client_exit)
quitButton.place(x=0, y=230)
# fileButton = Button(self, text='Browse Data Set', command=self.import_data)
# fileButton.place(x=150, y=0)
fileButton = Button(self, text='SBO', command=self.sbo)
fileButton.place(x=200, y=50)
fileButton = Button(self, text='CBO', command=self.cbo)
fileButton.place(x=150, y=50)
# menu = Menu(self.master)
# self.master.config(menu=menu)
#
# file = Menu(menu)
# file.add_command(label='Save',command=self.client_exit)
# file.add_command(label='Exit', command= self.client_exit)
# menu.add_cascade(label='File', menu=file)
#
# edit = Menu(menu)
# edit.add_command(label='Undo')
# menu.add_cascade(label='Edit', menu=edit)
def client_exit(self):
exit()
# def import_data(self):
#
# csv_file_path = askopenfilename()
# # print(csv_file_path)
# df = pd.read_excel(csv_file_path)
# return df
def sbo(self):
csv_file_path = askopenfilename()
df = pd.read_excel(csv_file_path)
data = df.drop(df.index[0]) # remove first row
data['BOVal%'] = data['BOVal%'].astype(str) # convert to string
data['BOQty%'] = data['BOQty%'].astype(str)
data['CustomerPONo'] = data['CustomerPONo'].astype(str)
data['OrdNo'] = data['OrdNo'].astype(str)
data['VendorNo'] = data['VendorNo'].astype(str)
pivot = data.pivot_table(index='Style', aggfunc='sum') # first pivot
pivoted = pd.DataFrame(pivot.to_records()) # flattened
pivoted = pivoted.sort_values(by=['BOVal'], ascending=False) # sort largest to smallest
pivoted['Ranking'] = range(1, len(pivoted) + 1) # Ranking
cols = pivoted.columns.tolist()
cols = cols[-1:] + cols[:-1]
pivoted = pivoted[cols]
pivoted = pivoted.set_index('Ranking')
col = df.columns.tolist()
col = (col[22:23] + col[15:17] + col[:14] + col[17:22] + col[23:37]) # rearrange column
data = df[col]
data = data.sort_values(by=['BOVal'], ascending=False) # sort value
data['Ranking'] = range(1, len(data) + 1) # Set rank
colm = data.columns.tolist()
colm = colm[-1:] + colm[:-1] # rearrange rank column
data = data[colm]
data = data.set_index('Ranking')
# sumboval = data['BOVal'].sum()
# sumboqty = data['BOQty'].sum()
# rounded = sumboval.round()
dates = data['SnapShotDate']
# print(dates)
dates = dates.iloc[1].strftime('%d%m%Y')
sos = data['SOS']
sos = sos[2]
result = pivoted.iloc[:10, :3]
# Create a Pandas Excel writer using XlsxWriter as the engine.
writer = pd.ExcelWriter('%s SBO %s .xlsx' % (sos, dates), engine='xlsxwriter')
# Write each dataframe to a different worksheet.
result.to_excel(writer, sheet_name='pivot')
df.to_excel(writer, sheet_name=dates)
data.to_excel(writer, sheet_name='SBO')
# Close the Pandas Excel writer and output the Excel file.
writer.save()
messagebox.showinfo("Note", "Calculation Completed")
def cbo(self):
csv_file_path = askopenfilename()
Stylemat = askopenfilename()
df = pd.read_excel(csv_file_path)
sm = pd.read_excel(Stylemat)
df = df.drop(df.index[0])
df.insert(loc=8, column='PH', value=['' for i in range(df.shape[0])])
df.insert(loc=9, column='Site', value=['' for i in range(df.shape[0])])
df['Region'] = df['Region'].fillna('"NA"')
df['S&OP Style Aggrt'] = df['S&OP Style Aggrt'].astype(str)
sm['Style'] = sm['Style'].astype(str)
dates = df['Date_Rp']
# print(dates)
dates = dates.iloc[1]
w = list(dates)
w[1] = '-'
w[3] = '-'
temp = w[0]
w[0] = w[2]
w[2] = temp
dates = "".join(w)
rowcount = len(df)
rowstyle = len(sm)
i = 0
j = 0
Style = []
for i in range(rowcount):
for j in range(rowstyle):
if df.iloc[i, 7] == sm.iloc[j, 0]:
df.iloc[i, 8] = 'Horizon'
df.iloc[i, 9] = sm.iloc[j, 2]
table = pd.pivot_table(df[df.PH == 'Horizon'], index='S&OP Style Aggrt', columns='Region',
values='Net CBO Value', aggfunc='sum')
table['Grand Total'] = table.sum(axis=1)
table = table.sort_values(by=['Grand Total'], ascending=False)
table['Ranking'] = range(1, len(table) + 1)
# Create a Pandas Excel writer using XlsxWriter as the engine.
writer = pd.ExcelWriter('CBO %s .xlsx' % dates, engine='xlsxwriter')
# Write each dataframe to a different worksheet.
table.to_excel(writer, sheet_name='pivot')
df.to_excel(writer, sheet_name=dates)
sm.to_excel(writer, sheet_name='StyleMat')
# Close the Pandas Excel writer and output the Excel file.
writer.save()
messagebox.showinfo("Note", "Calculation Completed")
root = Tk()
root.geometry('400x300')
app = Window(root)
root.mainloop()
I'd like to know how to find the main reason for this error and where to look for it, is it either my scripting method is incorrect or is there any additional file or module that I need. Appreciate in advance for your help. Thank you
I uninstalled everything related to win32 (pypiwin32, pywin32, pywin32-ctypes, pywinpty) and then installed again and magically it worked.
Took the idea from here and here.
this is quite late, but the answer to that issue is just the py to exe cannot execute on numpy 1.17. after downgrade to numpy 1.16, the program can run normally.
You are getting this error failed to execute script pyi_rth_win32comgenpy as result of not including the images you used for you icons and labels
I included images of icon, Question mark and the title
copy this images and include it the directory you have your pyi_rth_win32comgenpy executable.
I have a Excel as Below
|---------------------|------------------|
| Heading 1 | Heading 2 |
|---------------------|------------------|
| Row1 | Value 1 |
|---------------------|------------------|
| Row2 | Value 2 |
|---------------------|------------------|
I am reading from excel and Showing the Values of Heading 1 in the GUI
When I click on submit Button , I need to read the value/text of the CheckBox depending on the selection of the CheckBox and Create XML by using Excel for only selected values
Problem is How can I only select the values in the Excel , depending on the selection of check Box. (But I know how to identify which check box is checked ). But how to relate to Excel is I am facing problem
Note: I Know how to create XML from excel
I know how to identify when submit is clicked
GUI Code:
Config.Py
import tkinter as tk
import xlrd
import GetValueFromExcel
from GetValueFromExcel import ExcelValue
from array import array
from tkinter import *
from tkinter import ttk, Button
from tkinter import *
root = Tk()
class UICreation():
def __init__(self):
print ("I m in __init__")
self.tabControl = ttk.Notebook(root)
self.tab1 = ttk.Frame(self.tabControl)
self.tab2 = ttk.Frame(self.tabControl)
def tabcreation(self):
print ("I M in Tab Creation")
self.tabControl.add(self.tab1 , text="Tab1")
#self.tabControl(self.tab1, text= t)
##self.tabControl(self.tab1, )
self.tabControl.add(self.tab2, text="Tab2")
self.tabControl.grid()
def checkbox(self):
print ("I M in checkBox")
checkBox1 = Checkbutton(self.tab1, text=str(t[0]))
checkBox2 = Checkbutton(self.tab1, text=str(t[1]))
Checkbutton()
checkBox1.grid()
checkBox2.grid()
def button(self):
button = Button(self.tab1 , text="Submit", command=self.OnButtonClick)
button.grid()
def OnButtonClick(self):
print ("I am Working")
if __name__ == '__main__':
ui = UICreation()
ev = GetValueFromExcel.ExcelValue()
ev.readExcelValue()
t = ev.readExcelValue()
print(t)
ui.tabcreation()
ui.checkbox()
ui.button()
#ev = readExcelValue()
root.mainloop()
GetValueFromExcel.py
import xlrd
class ExcelValue():
def __init__(self):
self.wb=xlrd.open_workbook(r"C:\<FilePath>\Filename.xlsx")
#self.ws=self.wb.sheet_by_name("Sheet1")
for sheet in self.wb.sheets():
self.number_of_rows = sheet.nrows
self.number_of_columns = sheet.ncols
def readExcelValue(self):
result_data = []
row_data = []
for sheet in self.wb.sheets():
for curr_row in range(1, self.number_of_rows, 1):
#for curr_col in range(0, self.number_of_columns , 1):
#data = sheet.cell_value(curr_row, curr_col) # Read the data in the current cell
data = sheet.cell_value(curr_row, 0)
#print(data)
row_data.append(data)
result_data.append(row_data)
return result_data[1]
You can pass the value to Checkbutton like this:
def checkbox(self):
print ("I M in checkBox")
checkBox1 = Checkbutton(self.tab1, text=str(t.keys()[0]), variable=t.values()[0])
checkBox2 = Checkbutton(self.tab1, text=str(t.keys()[1]), variable=t.values()[1])
Checkbutton()
checkBox1.grid()
checkBox2.grid()
and you must change readExcelValue, like below:
def readExcelValue(self):
result_data = {}
for sheet in self.wb.sheets():
for curr_row in range(1, self.number_of_rows, 1):
data = sheet.cell_value(curr_row, 0)
value = sheet.cell_value(curr_row, 1)
result_data[data] = value
return result_data
I'm creating 3 groups of ttk.CheckButtons, using a class clsGrpCheckButton.
The problem is that I can access only the status of the last group created, and not for the previous group.
When clicking on one of the checkButtons of any group, I'm expecting to get the list of checkbuttons check in the group (by using method chkGrpGetValue with is the command parameter of each checkbutton)
However, whatever which button is clicked, the method only and always returns the status of the last group
Here is the code to recreate the issue, and in attachment a picture that shows the problems
Thks for your help.
Rgds
import tkinter as tk
from tkinter import ttk
import pandas as pd
class clsGrpCheckButton(ttk.Checkbutton):
def __init__(self,pContainer, pLstVal,pCommand,pInitValue=True):
self.grpChk=[0]*len(pLstVal)
self.grpKey=[0]*len(pLstVal)
self.grpLstVal = [0]*len(pLstVal)
self.grpVariable= [0]*len(pLstVal)
self.grpActiveKeys = [0]
for l,t in enumerate(pLstVal):
#l : index of the list of tuples
self.grpKey[l] = t[0]
self.grpLstVal[l] = t[1]
self.grpVariable[l] = tk.StringVar()
self.grpChk[l] = ttk.Checkbutton(pContainer, text=self.grpLstVal[l],
state='active' ,
onvalue= self.grpKey[l],
offvalue= '',
variable = self.grpVariable[l],
command=pCommand)
#get default value
if pInitValue :
self.grpVariable[l].set(self.grpKey[l])
self.grpActiveKeys.append(self.grpKey[l])
#get the index in the list of checkboxes
# depending on the key
def chkGrpGetIdx(self, pKey):
i=0
while i <len(self.grpKey):
if self.grpKey[i]==pKey :
return i
i=len(self.grpKey)
else:
i+=1
def chkGrpSetValue(self, pKey, pValue):
#need find correct index first
i=self.chkGrpGetIdx(pKey)
self.grpVariable[i] = pValue
#return the list of keys of the group
def chkGrpKeyLst(self):
return self.grpKey
#return the checkox element of the group of checkox
def chkGrpGetChkObj(self,pKey):
i=self.chkGrpGetIdx(pKey)
return self.grpChk[i]
#action when check/uncheck
#at list one element should be active
def chkGrpGetValue(self):
i=0
r=len(self.grpVariable)
self.grpActiveKeys.clear()
while i < len(self.grpVariable):
if self.grpVariable[i].get() =='':
r-=1
else:
self.grpActiveKeys.append(self.grpKey[i])
i+=1
if r==0:
self.grpVariable[0].set(self.grpKey[0])
self.grpActiveKeys.append(self.grpKey[0])
print(self.grpActiveKeys)
#to avoid accessing to class attribute directly
def chkGetCheckedValues(self):
return self.grpActiveKeys
class clsWindows(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
la = [1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,3]
lb= [10,11,12,14,15,20,21,22,23,24,25,26,30,31,32,33]
lc=['d10','d11','d12','d14','d15','d20','d21','d22','d23','d24','d25','d26','d30','d31','d32','d33']
df = pd.DataFrame(
{'DIVISION': la,
'DEPT_CODE': lb,
'DEPT_NAME': lc
})
lW = list(zip(df['DIVISION'].astype(str) , df['DEPT_CODE'].astype(str)))
lpt = list(zip(df['DEPT_CODE'].astype(str) , df['DEPT_NAME'].astype(str)))
curHead = ""
r=0
c=-1
for head, DPT in lW:
if not curHead==head:
curHead = head
c+=1
r=0
dq=df.query('DIVISION=='+head)
lpt = list(zip(dq['DEPT_CODE'].astype(str) , dq['DEPT_NAME'].astype(str)))
t=ttk.Labelframe(self,text=head)
t.grid(column=c, row=0, sticky='nw')
self.checkGrpDept= clsGrpCheckButton(t,lpt,lambda:self.checkGrpDept.chkGrpGetValue(),True)
self.checkGrpDept.chkGrpGetChkObj(DPT).grid(column=c, row=r, sticky='nw')
t.rowconfigure(r, weight=1)
t.columnconfigure(c, weight=1)
r+=1
def wQuit(self):
self.destroy()
app = clsWindows()
app.mainloop()
Example of issue
finally, I came up with a solution by using partial when assigning the command to each checkbutton.
Here is the full code if someone faces a similar issue
import tkinter as tk
from tkinter import ttk
import pandas as pd
from functools import partial
class clsGrpCheckButton():
def __init__(self,pContainer, pLstVal,pCommand,pInitValue=True):
self.grpChk=[0]*len(pLstVal)
self.grpKey=[0]*len(pLstVal)
self.grpLstVal = [0]*len(pLstVal)
self.grpVariable= [0]*len(pLstVal)
self.grpActiveKeys = [0]
for l,t in enumerate(pLstVal):
#l : index of the list of tuples
self.grpKey[l] = t[0]
self.grpLstVal[l] = t[1]
self.grpVariable[l] = tk.StringVar()
self.grpChk[l] = ttk.Checkbutton(pContainer, text=self.grpLstVal[l],
state='active' ,
onvalue= self.grpKey[l],
offvalue= '',
variable = self.grpVariable[l],
command=partial(pCommand,self))
#get default value
if pInitValue :
self.grpVariable[l].set(self.grpKey[l])
self.grpActiveKeys.append(self.grpKey[l])
#get the index in the list of checkboxes
# depending on the key
def chkGrpGetIdx(self, pKey):
i=0
while i <len(self.grpKey):
if self.grpKey[i]==pKey :
return i
i=len(self.grpKey)
else:
i+=1
def chkGrpSetValue(self, pKey, pValue):
#need find correct index first
i=self.chkGrpGetIdx(pKey)
self.grpVariable[i] = pValue
#return the list of keys of the group
def chkGrpKeyLst(self):
return self.grpKey
#return the checkox element of the group of checkox
def chkGrpGetChkObj(self,pKey):
i=self.chkGrpGetIdx(pKey)
return self.grpChk[i]
#action when check/uncheck
#at list one element should be active
def chkGrpGetValue(self):
i=0
r=len(self.grpVariable)
self.grpActiveKeys.clear()
while i < len(self.grpVariable):
if self.grpVariable[i].get() =='':
r-=1
else:
self.grpActiveKeys.append(self.grpKey[i])
i+=1
if r==0:
self.grpVariable[0].set(self.grpKey[0])
self.grpActiveKeys.append(self.grpKey[0])
print(self.grpActiveKeys)
#to avoid accessing to class attribute directly
def chkGetCheckedValues(self):
return self.grpActiveKeys
class clsWindows(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
la = [1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,3]
lb= [10,11,12,14,15,20,21,22,23,24,25,26,30,31,32,33]
lc=['d10','d11','d12','d14','d15','d20','d21','d22','d23','d24','d25','d26','d30','d31','d32','d33']
df = pd.DataFrame(
{'DIVISION': la,
'DEPT_CODE': lb,
'DEPT_NAME': lc
})
lW = list(zip(df['DIVISION'].astype(str) , df['DEPT_CODE'].astype(str)))
lpt = list(zip(df['DEPT_CODE'].astype(str) , df['DEPT_NAME'].astype(str)))
curHead = ""
r=0
c=-1
for head, DPT in lW:
if not curHead==head:
curHead = head
c+=1
r=0
dq=df.query('DIVISION=='+head)
lpt = list(zip(dq['DEPT_CODE'].astype(str) , dq['DEPT_NAME'].astype(str)))
t=ttk.Labelframe(self,text=head)
t.grid(column=c, row=0, sticky='nw')
checkGrpDept= clsGrpCheckButton(t,lpt,clsGrpCheckButton.chkGrpGetValue,True)
checkGrpDept.chkGrpGetChkObj(DPT).grid(column=c, row=r, sticky='nw')
t.rowconfigure(r, weight=1)
t.columnconfigure(c, weight=1)
r+=1
def wQuit(self):
self.destroy()
app = clsWindows()
app.mainloop()
I'm trying to create a custom ComboBox that behaves like the one in here: http://chir.ag/projects/name-that-color/
I've got two problems right now:
I can't seem to find a way to have a scrollbar on the side; the gtk.rc_parse_string function should do that, since the ComboBox widget has a "appears-as-list" style property, but my custom widget seems unaffected for some reason.
When you select a color from my widget, then click the ComboBox again, instead of showing the selected item and its neighbours, the scrolled window starts from the top, for no apparent reason.
This is the code, you can pretty much ignore the __load_name_palette method. You need the /usr/share/X11/rgb.txt file to run this code, it looks like this: http://pastebin.com/raw.php?i=dkemmEdr
import gtk
import gobject
from os.path import exists
def window_delete_event(*args):
return False
def window_destroy(*args):
gtk.main_quit()
class ColorName(gtk.ComboBox):
colors = []
def __init__(self, name_palette_path, wrap_width=1):
gtk.ComboBox.__init__(self)
liststore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING,
gobject.TYPE_STRING)
name_palette = self.__load_name_palette(name_palette_path)
for c in name_palette:
r, g, b, name = c
if ((r + g + b) / 3.) < 128.:
fg = '#DDDDDD'
else:
fg = '#222222'
bg = "#%02X%02X%02X" % (r, g, b)
liststore.append((name, bg, fg))
self.set_model(liststore)
label = gtk.CellRendererText()
self.pack_start(label, True)
self.set_attributes(label, background=1, foreground=2, text=0)
self.set_wrap_width(wrap_width)
if len(name_palette) > 0:
self.set_active(0)
self.show_all()
def __load_name_palette(self, name_palette_path):
if exists(name_palette_path):
try:
f = open(name_palette_path,'r')
self.colors = []
palette = set()
for l in f:
foo = l.rstrip().split(None,3)
try:
rgb = [int(x) for x in foo[:3]]
name, = foo[3:]
except:
continue
k = ':'.join(foo[:3])
if k not in palette:
palette.add(k)
self.colors.append(rgb + [name])
f.close()
return self.colors
except IOError as (errno, strerror):
print "error: failed to open {0}: {1}".format(name_palette_path, strerror)
return []
else:
return []
if __name__ == '__main__':
win = gtk.Window()
#colname = ColorName('./ntc.txt')
colname = ColorName('/usr/share/X11/rgb.txt')
gtk.rc_parse_string("""style "mystyle" { GtkComboBox::appears-as-list = 1 }
class "GtkComboBox" style "mystyle" """)
print 'appears-as-list:', colname.style_get_property('appears-as-list')
model = gtk.ListStore(gobject.TYPE_STRING)
hbox = gtk.HBox()
win.add(hbox)
hbox.pack_start(colname)
win.connect('delete-event', window_delete_event)
win.connect('destroy', window_destroy)
win.show_all()
gtk.main()
The problem was the self.show_all() line. Also, you can't have a list AND a wrap_width != 1