Python tkinter: table with variable row height possible? - python

For my sqlite-based search Python script (a kind of two-language translation dictionary, i.e. translation memory), I've decided to use tkinter and show results in a treeview.
Everything works OK, except for the fact that for longer strings, text gets truncated: table rows are always 1 line high. If I change row height, it then applies to the whole treeview, which is not what I want.
Judging from Brian Oakley's answer here:
How to change height of only one row in a Treeview?
it seems that having variable row heights in a treeview is not possible.
So, my question is whether it is possible (using tkinter) to have a table with e.g. 3-4 columns, in which I can vary row height, depending on number of lines of wrapped text?
Perhaps something using listboxes or labels?
This is what I have now with treeview:
And this is what I would like to have (note different row heights in the table - this was done in Perl/Tk):
So, is there any way to have such table with variable row heights, using Python and tkinter?

Related

Using python code to set stimuli to certain locations from excel conditions file

I am a final year undergraduate doing my dissertation. I am replicating Reagh's (2016) Mnemonic Similarity Task and am struggling with coding for the Spatial Task.
What I want to achieve is all stimuli coded '5' in my excel file to appear on the left hand side of the screen and all stimuli coded '10' to appear on the right. I've built the rest of my study via builderview and have tried multiple ways of coding this but haven't been successful. Sorry if this is a silly question but am very new to this and have watched and read many things to try and help me - any help at all would be appreciated :) I've added a link to a photo of my excel conditions file.
SpatialStudy.csv
If you have the data in a pandas dataframe, you can use the pivot method with columns='LeftRight' to reorganize the data so there is a column for each unique value within the Left right column.
For reading the file you could use pandas
and for printing a write should do
import pandas as pd
#reads the csv
df = pd.read_csv("yourfile")
#gets all of the ones with 5 on the leftright column
right = df.loc[df['LeftRight'] == 5]
#gets all of the ones with 10 on the leftright column
left = df.loc[df['LeftRight'] == 10]
# for the prinring part i dont know if you mean on the right of the output page or you want a black screen so this is just for the output page
sys.stdout.write("%-6s %-50s %-25s\n" % (right, left))
Insert a code component (from the "custom" component panel in the Builder interface). In its "Begin experiment" tab, insert something like this to map your variable's contents to a position on screen:
position_map = {5:-200, 10:200}
i.e. we have created a dictionary that will return the corresponding horizontal position when fed a value of either 5 or 10. Note that I've used arbitrary positions of -200 and 200 pixels. Replace with whatever values make sense for your stimulus and chosen units.
Then in the relevant stimulus component, put something like this in its "position" field, and set that field to update every repeat:
(position_map[LeftRight], 0)
PS in the future you might find it better to take queries like this to the dedicated support forum at https://discourse.psychopy.org. StackOverflow can be quite fussy about questions that aren't really programming-based.

Tkinter - Return column number of selected treeview

How do I get the number of the column that is selected in a tkinter treeview?
Right now I'm using tree.focus() but it returns something like I001 or I00A and I have no idea how to convert that to a number.
I can't index the tree because there are multiple items with the same name in it, and I want to know the exact column the user clicks on.
What I expect is to click the first item and get the integer 0 back, etc.
Thanks, please ask questions if I was confusing...
Here are docs for Treeview.
You have used the term "column" repeatedly, but when you say "multiple items with the same name" and refer to "first item" it sounds a lot like you're talking about rows.
If you want the column, you'll need to capture the click event using treeview.bind("<Button-1>", callback) or a variant of that. You would then use treeview.identify_column to get the column index based on the event's x location (keep in mind, per the docs, that if your columns are rearranged you may need to do some extra work). Here are two links if you need information on events.
If you were actually talking about rows, you can use treeview.selection() to get a list of iids of selected items, and then feed them into treeview.index() to get the 0-index of the row that you were talking about.

how can i change the size of a table in word using python (pywin32)

ms word table with python
I am working with python on word tables, i am generating tables, but all of them are
auto fit window..
is it possible to change it to auto fit contents?
i had tried something like this:
table = location.Tables.Add(location,len(df)+1,len(df.columns)
table.AutoFit(AutoFitBehavior.AutoFitToContents)
but it keeps to raise errors
You want to change you table creation to use this:
//''#Add two ones after your columns
table = location.Tables.Add(location,len(df)+1,len(df.columns),1,1)
Information about why you need those variables can be read here:
http://msdn.microsoft.com/en-us/library/office/ff845710(v=office.15).aspx
But basically, the default behavior is to disable Cell Autofitting and Use Table Autofit to Window. The first "1" enables Cell Autofitting. From the link I posted above, the DefaultTableBehavior can either be wdWord8TableBehavior (Autofit disabled --default) or wdWord9TableBehavior (Autofit enabled). The number comes from opening up Word's VBA editor and typing in the Immediate Window:
?Word.wdWord9TableBehavior
Next, from the link, we see another option called AutoFitBehavior. This is defined as:
Sets the AutoFit rules for how Word sizes tables. Can be one of the WdAutoFitBehavior constants.
So now we have another term to look up. In the VBA editor's Immediate window again type:
?Word.wdAutoFitBehavior.
After the last dot, the possible options should appear. These will be:
wdAutoFitContent
wdAutoFitFixed
wdAutoFitWindow
AutoFitContent looks to be the option we want, so let's finish up that previous line with:
?Word.wdAutoFitBehavior.wdAutoFitContent
The result will be a "1".
Now you may ask, why do we have to go through all this trouble finding the numerical representations of the values. From my experience, with using pywin32 with Excel, is that you can't get the Built-in values, from the string, most of the time. But putting in the numerical representation works just the same.
Also, One more reason for why your code may be failing is that the table object may not have a function "Autofit".
I'm using Word 2007, and Table has the function, AutoFitBehavior.
So Change:
table.AutoFit(AutoFitBehaviour.AutoFitToContent)
To:
table.AutoFitBehavior(1)
//''Which we know the 1 means wd.wdAutoFitBehavior.wdAutoFitContent
Hope I got it right, and this helps you out.

How to align columns with multiple Tkinter checkbuttons?

I try to put sixteen checkbuttons into frame, placing them into four columns like:
c1 = Tkinter.Checkbutton(group.interior(), text = 'Name', indicatoron= 1, variable = self.Checkvar_nr, command=cb)
c1.(row = 0, column = 0)
and so on up to:
c16.(row = 3, column = 3)
Everything's fine except columns vertical alignment because of the differences in the length of the text used.
How to align then horizontally?
I don't quite understand the problem, since columns must be vertically aligned since it's a grid. I think what you're saying is that the items in each column aren't aligned to a column boundary. Try using sticky='w' when adding each checkbutton to the grid. This will cause them to "stick" to the left edge of the column.
As an option, try placing each element in a non-stretchable graphic element.
The thought is that the layout manager is maximizing the use of the screen real estate. Because you want to take up more space, which is contrary to the layout manager's algorithm, you will need to find a graphic container that doesn't "change size".
Sometimes you can do this through manually editing the text string (less preferred). Other times you can use a table like structure (HTML for instance). Other times you can use a frame with defined width and height attributes. These frames are then placed inside of the columns as elements.
Note: It's been a long time since I played with Tk. I'm going by memory. Best of luck!
(edit:) Going from memory, the columns will adjust their width based on content. If there are several three character labels in the first column and five character labels in the second column, the width of the two columns will be different. (Note: This will be depended on the layout manager.) If there is a 'fixed width' option for the layout manager in question, then it should keep all column widths the same.
With layout managers that rearrange with dimensions based on content (HTML, CSS, etc), it is sometimes necessary to place the content inside "immovable" containers. Usually these are frames. The frames work as bounding boxes. This approach works when the element that needs to have a width and height does not have that feature.

Scroll QTableWidget to specific column

I have a bunch of data in a QTableWidget and I would like to be able to scroll to a particular column. I'm currently using scrollToItem(self.item(0, col)). However, this hardcodes the row to 0. It causes problems if a user is looking at row 100 and scrolls to a specific column since it loses their vertical place in the table.
Is there a way to find what row the user is currently viewing inside of the QScrollArea that the QTableWidget provides? If so, I could easily replace that defaulted row with the correct one.
Maybe there is another way to achieve this result with something like .ensureWidgetVisible()? However, I'm not sure how to get the correct widget that I would want to scroll to or make visible.
One way to do this is to get the row-index of the first visible row, and then use that to find the first visible item in the column you want to scoll to:
def scrollToColumn(self, column=0):
visible = self.itemAt(0, 0)
if visible is not None:
self.scrollToItem(self.item(visible.row(), column))
Since the row of the item you're scrolling to is already visible, the view should not scroll itself vertically (unless the verticalScrollMode is ScrollPerPixel and the item at point (0, 0) is not fully visible).

Categories

Resources