Has anyone worked with tkinter table?
I have problem with adding data into new row. I have an entry field in which user enter object. Then in def onButtonSents() I check if this word is contained in objects array and enter this object into the first column of the table naming Object, in the second column I add positive sentiments of the object and so on. I want by clicking the button add new row and put in different columns of one row values of dictionary. Here what I have for now:
file sentiment_analysis.py:
objects [] #an array of objects which user enters into entry field
positiveSentiments = dict() #dictionary with key - object and positive words which correspond to it
negativeSentiments = dict() #dictionary with key - object and negative words which correspond to it
array_cols = ['Object', 'Positive sentiments', 'Negative sentiments']
var = tktable.ArrayVar()
#below is initialization of my tkinter table
import tktable
array_cols = ['Object', 'Positive sentiments', 'Negative sentiments']
var = tktable.ArrayVar()
table = tktable.Table(frame,
rows = 1,
cols = 3,
roworigin=0,
colorigin=0,
variable=var,)
table.pack(side='bottom', fill='both')
var.set(index='0,0', value = 'Object')
table.tag_configure('active', )
var.set(index='0,1', value = 'Positive Sentiments')
var.set(index='0,2', value = 'Negative Sentiments')
#The method which puts data into the rows of table
def onButtonSents():
table.insert_rows(1)
for i in range (1, 5):
index1 = '%i,%i' % (i, 0)
table.activate(index1)
for key in sentiment_analysis.positiveSentiments.keys():
if key == entry.get():
var.set(index='active', value=entry.get())
for i in range (1, 5):
index2 = '%i,%i' % (i, 1)
table.activate(index2)
for key in sentiment_analysis.positiveSentiments.keys():
if key == entry.get():
var.set(index='active', value=sentiment_analysis.positiveSentiments[key])
for i in range (1, 5):
index3 = '%i,%i' % (i, 2)
table.activate(index3)
for key in sentiment_analysis.negativeSentiments.keys():
if key == entry.get():
var.set(index='active', value=sentiment_analysis.negativeSentiments[key])
But the cells of table aren't correctly filled. First object if filled correctly but then all objects become the same like first I enter 'ubs' and when I enter the second 'wheat' the first also becomes 'wheat' and their sentiments are also changed.
Unfortunately I haven't found any suggestions for this problem in the Internet. I would be very grateful for any advice!
Below I have included my rewrite of your code to work the way you intended.
This runs properly for me.
Let me know if it works for you.
Please Note: I am using Python 3.6, tkinter and tktable.
Before I show the code, I will give a brief explanation of the tktable syntax for setting data into a row.
Your code was on the right track, but there were some errors preventing it from working.
Your first error was to use "var.set" to set data to the tktable array variable.
Instead, you should have been using "table.set" to set data to the tktable "table" pathname variable.
Secondly, because you are setting data to a row, you can use the set 'row' option.
Thirdly, you do Not need to specify "index=" and "value=".
You can simply enter the index and value, separated by commas.
If you have created variables for the index and value, you can use the variable names.
To set multiple values to multiple indexes on the same row,
you simply add more values, separated by commas.
You only need to specify the index of the first cell in this row.
For example:
You wrote:
var.set(index='active', value=entry.get())
This should be:
table.set('row', '1,0', entry.get(), 'Positive Sentiments', 'Negative Sentiments')
The above line presumes you want this 'row' to begin at cell index '1,0'.
The code you provided did not run for me.
Therefore, to get the code to run as intended, I have added a class structure.
If you have questions about classes and how to use them, most of these questions have already been answered in detail on Stack Overflow by Bryan Oakley and others.
The class structure I have added to your code is based on what I have learnt from Bryan Oakley via Stack Overflow.
Also, I made other changes as follows:
Amended your onButtonSents method, by changing the conditional statements, and correcting the "insert_rows" syntax,
so that the correct data is added to the next new line as you specified.
If you have any questions about this, please let me know.
Added some test sample data to the "objects" list and for the dictionaries: "positiveSentiments" and "negativeSentiments',
to demonstrate how the code works.
Since you have Not specified how you would like the code to behave when the user inputs an object that is Not on the list,
I have left this for you to do yourself.
Here is the revised code:
import tkinter as tk
import tktable
from tkinter import Tk, Label, Button
from tkinter import *
class Control(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.controller = self
self.shared_data = {
"objects": tk.Variable(),
"positiveSentiments": tk.Variable(),
"negativeSentiments": tk.Variable(),
"x": tk.IntVar(),
}
self.title('Title of Control Class')
self.entry_frame = tk.Frame()
self.entry_frame.pack(side=TOP)
self.user_input = tk.StringVar()
self.test_entry = tk.Entry(self.entry_frame, textvariable=self.user_input)
self.test_entry.pack(side=LEFT)
self.test_button = tk.Button(self.entry_frame, text='Button', command=self.onButtonSents)
self.test_button.pack(side=RIGHT)
self.table_frame = tk.Frame()
self.table_frame.pack(side=BOTTOM)
self.array_cols = ['Object', 'Positive sentiments', 'Negative sentiments']
self.var = tktable.ArrayVar()
self.table = tktable.Table(self.table_frame,
rows = 1,
cols = 3,
roworigin=0,
colorigin=0,
colwidth=20,
variable=self.var,)
self.table.pack(side='bottom', fill='both', expand=True)
self.table.set('row', '0,0', 'Object','Positive Sentiments', 'Negative Sentiments')
self.table.tag_configure('active', )
self.shared_data["objects"] = ['object1', 'object2', 'object3', 'object4', 'object5', 'object6', 'object7'] #an array of objects which user enters into entry field
self.shared_data["positiveSentiments"] = {'object1' : 'positive1', 'object2' : 'positive2', 'object3' : 'positive3', 'object4' : 'positive4', 'object5' : 'positive5', 'object6' : 'positive6', 'object7' : 'positive7' } #dictionary with key - object and positive words which correspond to it
self.shared_data["negativeSentiments"] = {'object1' : 'negative1', 'object2' : 'negative2', 'object3' : 'negative3', 'object4' : 'negative4', 'object5' : 'negative5', 'object6' : 'negative6', 'object7' : 'negative7'} #dictionary with key - object and negative words which correspond to it
#The method which puts data into the rows of table
def onButtonSents(self, _event=None):
#self.table.insert_rows(1)
for o in self.shared_data["objects"]:
if o == self.user_input.get():
if o in self.shared_data["positiveSentiments"]:
if o in self.shared_data["negativeSentiments"]:
if self.shared_data["x"].get() is not None:
self.shared_data["x"].set(self.shared_data["x"].get() + 1)
self.index1 = '%i,%i' % (self.shared_data["x"].get(), 0)
self.table.insert_rows(self.shared_data["x"].get() - 1, 1)
self.table.set('row', self.index1, self.user_input.get(), self.shared_data["positiveSentiments"].get(o), self.shared_data["negativeSentiments"].get(o))
else:
self.shared_data["x"].set(1)
self.index1 = '%i,%i' % (self.shared_data["x"].get(), 0)
self.table.set('row', self.index1, self.user_input.get(), self.shared_data["positiveSentiments"].get(o), self.shared_data["negativeSentiments"].get(o))
Control1 = Control()
Control1.mainloop()
Related
I'm working on a program that will be used for internally ordering parts between stores. Currently I have the GUI working perfectly, and the code has no errors.
I want to have a button at the bottom of the GUI that will say send, which will read the selections made, and then export those into a file that can be read by the logistics department. I have scoured the internet but cant seem to find such thing for python.
I would prefer it to export the selections into a excel spreadsheet, but text file will do too, if it can be coded so that it would be easy to read.
As I received a bad comment on the last post, I'll post code for the two kinds of selection boxes, i have. The code pasted into a .py file will open a similar GUI.
from tkinter import *
from tkinter.ttk import *
master = Tk()
master.geometry("400x400")
def openiPhone5():
iPhone5 = Toplevel(master)
iPhone5.geometry("800x800")
Label(iPhone5,
text="iPhone 5").grid()
#Variabel til iPhone 5 Farver
iPhone5Colors =('Sort', 'Hvid')
#PARTS###
#OrginalSkærm
OGscreen = Combobox(iPhone5)
OGscreenColor = Combobox(iPhone5)
OGscreen['values'] = (1, 2, 3, 4, 5, "Text")
OGscreenColor['values'] = iPhone5Colors
OGscreen.current(0) # set the selected item
OGscreenColor.grid(column=3, row=7)
#CUSTOM
CustomAmount = Combobox(iPhone5)
CustomTEXT = Combobox(iPhone5)
CustomTEXT['text'] = (1, "Text")
CustomAmount['values'] = (1, 2, 3, 4, 5, "Text")
CustomAmount.current(0) # set the selected item
CustomAmount.grid(column=3, row=18)
CustomTEXT.grid(column=3, row=17)
Custom_lbl = Label(iPhone5,
text="Custom")
Custom_lbl.grid(column=1, row=17)
def openNewWindow1():
# Toplevel object which will
# be treated as a new window
newWindow1 = Toplevel(master)
# sets the title of the
# Toplevel widget
newWindow1.title("Apple")
# sets the geometry of toplevel
newWindow1.geometry("800x800")
# A Label widget to show in toplevel
Label(newWindow1,
text="iPhones").grid()
btn = Button(newWindow1,
text="iPhone 5",
command=openiPhone5)
The simplest way is to start by associating a variable with each combobox. You can then store those variables in a list or dictionary. To get the data out it's just a matter of iterating over the list or dictionary and calling get on each variable.
Here's an example of a very simplistic example that creates 10 comboboxes with associated variables:
combo_vars = []
for i in range(10):
var = tk.StringVar(root, value=0)
combo_vars.append(var)
label = tk.Label(form, text=f"Value {i+1}:")
combo = ttk.Combobox(form, textvariable=var, width=20, values=list(range(5)))
label.grid(row=i, column=0, sticky="e")
combo.grid(row=i, column=1, sticky="w")
For example, assuming you have a variable named combo_vars that contains instances of StringVar such as in the previous example, you can get all of the values and print them out in a simple loop. There's a more concise way of doing this using list comprehensions, but I'm using the more verbose method to make it easier to understand.
values = []
for var in combo_vars:
value = var.get()
values.append(value)
With that, values has a list of the values. You can then do whatever you want with that list: convert them to a comma-separated list, write them to a database, convert them to json, save them to an excel file, or whatever it is you need to do.
For example, to write a comma-separated list to a file you can use the csv module like so:
import csv
...
with open("data.csv", "w") as csvfile:
writer = csv.writer(csvfile, values)
writer.writerow(values)
I have provided this data frame,
as you see I have 3 index chapter, ParaIndex, (paragraph index) and Sentindex (sententcesindex), I have 70 chapters, 1699 Paragraph, and 6999 sentences
so each of them starts from the beginning (0 or 1 ), the problem is that I want to make a widget to call a "specific sentence" which placed in a specific paragraph of a chapter. something like this
https://towardsdatascience.com/interactive-controls-for-jupyter-notebooks-f5c94829aee6
but for extracting specific sentences in the specific paragraph of the specific chapter
I think I should have another index (like ChapParaSent ABBREVIATION for all) or even multidimensions index which show that this sentence where exactly placed
any idea how can I provide that using ipywidget
https://ipywidgets.readthedocs.io/en/latest/examples/Using%20Interact.html
#interact
def showDetail( Chapter=(1,70),ParaIndex=(0,1699),SentIndex=(0,6999)):
return df.loc[(df.Chapter == Chapter) & (df.ParaIndex==ParaIndex)&(df.SentIndex==SentIndex)]
the problem with this is since we do not know each chapter has how many paragraphs has as well as and we do not know in each paragraph SentIndex the index to start from which number most of the time we have no result.
the aim is to adopt this (or define a new index) in a way that with changing the bar buttons we have always one unique sentence
for example, here I have the result:
but when I changed to this :
I do not have any result, the REASON is obvious because we do not have any index as 1-2-1 since, in chapter 1, Paragraph index 2: Sentindex starts from 2!
One solution I saw that it was a complete definition of a multidimensional data frame but I need something easier that I can use by ipywidget...
many many thanks
Im sure there is a easier solution out there but that works I guess.
import pandas as pd
data = [
dict(Chapter=0, ParaIndex=0, SentIndex=0, content="0"),
dict(Chapter=1, ParaIndex=1, SentIndex=1, content="a"),
dict(Chapter=1, ParaIndex=1, SentIndex=2, content="b"),
dict(Chapter=2, ParaIndex=2, SentIndex=3, content="c"),
dict(Chapter=2, ParaIndex=2, SentIndex=4, content="d"),
dict(Chapter=2, ParaIndex=3, SentIndex=5, content="e"),
dict(Chapter=3, ParaIndex=4, SentIndex=6, content="f"),
]
df = pd.DataFrame(data)
def showbyindex(target_chapter, target_paragraph, target_sentence):
df_chapter = df.loc[df.Chapter==target_chapter]
unique_paragraphs = df_chapter.ParaIndex.unique()
paragraph_idx = unique_paragraphs[target_paragraph]
df_paragraph = df_chapter.loc[df.ParaIndex==paragraph_idx]
return df_paragraph.iloc[target_sentence]
showbyindex(target_chapter=2, target_paragraph=0, target_sentence=1)
Edit:
If you want the sliders only to be within a valid range you can define IntSliders for your interact decorator:
chapter_slider = widgets.IntSlider(min=0, max=max(df.Chapter.unique()), step=1, value=0)
paragraph_slider = widgets.IntSlider(min=0, max=1, step=1, value=0)
sentence_slider = widgets.IntSlider(min=0, max=1, step=1, value=0)
#interact(target_chapter=chapter_slider, target_paragraph=paragraph_slider, target_sentence=sentence_slider)
Now you have to check the valid number of paragraphs/sentences within your showbyindex function and set the sliders value/max accordingly.
if(...):
paragraph_slider.max = ...
...
Thanks for taking a moment to read this! So, my first issue is that I'm trying to create a function, "selectionData()", to get an object's translate, rotate, and scale values and then return them as a dictionary, but find myself struggling a bit. Using the code listed below, all I keep getting is the object's name. How can I modify it to get its translate, rotate, and scale values to return as a dictionary?
My second issue is that I'm trying to create a function, "setData(data)", that takes as input the aforementioned dictionary built with selectionData() and restores the data in the dictionary to the selected objects. How do I do that?
My apologies if either of these questions are foolish, but thank you for your time, regardless! Cheers!
Current code is listed below:
from maya import cmds
sel = cmds.ls(sl = 1)
meshes =[]
for s in sel :
shape = cmds.listRelatives(s , shapes = 1 )
if shape :
if cmds.nodeType(shape[0]) == "mesh" :
meshes.append(s )
meshData = {}
for m in meshes :
pos = cmds.xform ( m , q =1 , ws = 1 , t = 1)
rot = cmds.xform( m , q =1 , ws = 1 , rotation = 1 )
scl = cmds.getAttr ( m + '.s' )[0]
currentDict = {
"pos" : pos ,
"rot" : rot ,
"scl" : scl ,
}
meshData[m] = currentDict
def selectionData( selectionDict):
for k in selectionDict :
print k
selectionData(meshData)
First of all, to list all the objects with transforms you can use this command:
cmds.ls(selection=True, transforms=True, dagObjects=True)
If you want to read/write the transforms, you don't need to get the translation, then rotation and scale separately. You can read the composite transformation matrix like this:
xform_matrix = cmds.xform(source_object, query=True, matrix=True)
You'll get a list of 16 float numbers that are ready to be applied to other objects:
cmds.xform(destination_object, matrix=xform_matrix)
I am not sure how do you want to map the transforms from one set of selected objects to another set. If you describe, I'll be able to post the complete code.
The following script will collect the composite transformation matrix of all selected objects in the dictionary with long object names as the keys:
selected_objects_matrix = {}
for current_object in cmds.ls(selection=True, transforms=True, dagObjects=True):
selected_objects_matrix[cmds.ls(current_object, long=True)] = cmds.xform(
current_object,
query=True,
matrix=True)
Then if you move/rotate/scale the objects in Maya, you can revert like that:
for current_object in selected_objects_matrix:
cmds.xform(
current_object,
matrix=selected_objects_matrix[current_object])
you really just want to do what you have in reverse
setting the q=1 sets the command into query mode.
removing this flag defaults the command to edit mode
getAttr and setAttr are their respective commands, however you need to be aware of the data that youre setting. even though youre grabbing the s attribute above youre making that only grab the x value so when you set it you need to specify sx
cmds.xform ( m , ws = 1 , t = posValues)
cmds.xform( m , ws = 1 , rotation = rotValues )
cmds.setAttr ( m + '.sx', scaleValue) # sx because you are only grabbing the X Value
I'm trying to make an array/list of tkinter Labels for a wage calculator, but whenever I append the widget to my array, it appends as an int datatype. I was thinking appending it would allow me to call list[widgetIndex].grid() but since it wasn't a Label datatype getting appended to my list for some reason, it gives me an error saying that this 'int' object has no attribute called 'grid'. Why is it an int datatype as oppose to the Label datatype that the variable definitely was before I appended it?
def addJob(jc, cc, he, wl, hl, we):
jc = jc + 1
cc = cc + 2
wageLabel = Label(root, text="Wage")
hoursLabel = Label(root, text="Hours")
wageEntry = Entry(root)
hoursEntry = Entry(root)
wl.append(wageLabel)
hl.append(hoursLabel)
we.append(wageEntry)
he.append(hoursEntry)
wl[jc-1].grid(row =0, column =cc-1, sticky=E)
hl[jc-1].grid(row =1, column =cc-1, sticky=E)
we[jc-1].grid(row = 0, column=cc)
he[jc-1].grid(row = 1, column=cc)
You initialize w1 using w1 = [ 0 ].
Later on you just append to w1, so your list will be sth. like
[ 0, <class 'tkinter.Label'>, <class 'tkinter.Label'>, <class 'tkinter.Label'>, ... ] depending on how many labels you add.
Using w1 = [] will solve your problem.
The error occurs as the first element in your list ("0") cannot be gridded.
Using print w1 in your function would have shown you this in a fairly easy way.
Bryan is right, the code you posted is without a doubt okay for the purpose you intend using it, but the initialization for your passed parameters (not posted as code sample) defines a different behaviour.
Please read on How to create a Minimal, Complete and Verifiable Example. Breaking down code into the smallest piece still reproducing the error mostly guides you direct to the solution.
Hello I'm trying to get this program to print out the list data for the corridor entered in the class call at the bottom. But it only prints out the very last row in the list. This program takes in a .csv file and turns into a list. Not by any means a very experienced python programmer.
class csv_get(object): # class to being in the .csv file to the program
import os
os.chdir('C:\Users\U2970\Documents\ArcGIS')
gpsTrack = open('roadlog_intersection_export_02_18_2014_2.csv', 'rb')
# Figure out position of lat and long in the header
headerLine = gpsTrack.readline()
valueList = headerLine.split(",")
class data_set(object): # place columns from .csv file into a python dictionary
dict = {'DESC' : csv_get.valueList.index("TDD_DESC"),
'ROUTE_NAME' : csv_get.valueList.index("ROUTE_NAME"),
'CORRIDOR': csv_get.valueList.index("CORRIDOR"),
'ROADBED': csv_get.valueList.index("DC_RBD"),
'BEG_RP': csv_get.valueList.index("BEG_RP"),
'END_RP': csv_get.valueList.index("END_RP"),
'DESIGNATION': csv_get.valueList.index("NRLG_SYS_DESC")}
class columns_set(object): # append the dict into a list
new_list = []
for line in csv_get.gpsTrack.readlines():
segmentedLine = line.split(",")
new_list.append([segmentedLine[data_set.dict['DESC']],\
'{:>7}'.format(segmentedLine[data_set.dict['ROUTE_NAME']]),\
'{:>7}'.format(segmentedLine[data_set.dict['CORRIDOR']]),\
'{:>7}'.format(segmentedLine[data_set.dict['ROADBED']]),\
'{:>7}'.format(segmentedLine[data_set.dict['BEG_RP']]),\
'{:>7}'.format(segmentedLine[data_set.dict['END_RP']]),\
'{:>7}'.format(segmentedLine[data_set.dict['DESIGNATION']])])
class data:
def __init__(self,corridor):
for col in columns_set.new_list: # for each column in the list new_list
self.desc = col[0]
self.route = col[1] # assigns column names to column numbers
self.corridor = col[2]
self.roadbed = col[3]
self.beg_rp = col[4]
self.end_rp = col[5]
self.designation = col[6]
def displayData(self): # print data for corridor number entered
print self.desc,\
self.route,\
self.corridor,\
self.roadbed,\
self.beg_rp,\
self.end_rp,\
self.designation
set1 = data('C000021') # corridor number to be sent into data class
# should print all the corridor data but only prints very last record
set1.displayData()
You're only storing data from the current row, and overwriting it with each row. A line like self.desc = col[0] says "overwrite self.desc so it refers to the value of col[0].
I hate to say it, but all of this code is flawed at a fundamental level. Your classes, except for data, are really functions. And even data is defective because it pulls in hardwired elements from outside itself.
You really should use Python's included CSV module to parse a CSV file into lists of lists. It can even give you a list of dictionaries and handle the header line.