Tkinter: How to bind a Shift - python-3.x

I'm making a menubar in Tkinter with an accelerator:
menubar = tk.Menu(window)
file_menu = tk.Menu(menubar)
menubar.add_cascade(label='File', menu=file_menu)
window.config(menu=menubar)
file_menu.add_command(label='Open resource pack', command=openPack, accelerator='Cmd+o' if IS_MAC else 'Ctrl+o')
window.bind_all('<M1-o>' if IS_MAC else '<Control-o>', openPack)
file_menu.add_command(label='Copy original pack', command=copyOriginalPack, accelerator='Shift+Cmd+c' if IS_MAC else 'Shift+Ctrl+c')
window.bind_all('<M1-C>' if IS_MAC else '<Control-C>', copyOriginalPack)
But for the Copy original pack option the key combination is Shift + Command + C. The accelerator only shows the key combination in the menubar but doesn't actually run the command, so I have to manually bind to the window.
If I remember correctly, to bind Shift + Command + C I just need to say Control+C and make the C uppercase because of Shift.
But I can't bind Shift. It works if I click the menu option, but the key combo doesn't. It works for the other option, which doesn't have Shift

I fixed it by writing <M1-Shift-c> (note the lowercase c)

Related

Tkinter Listbox: programmatically selecting Listbox item disables up/down cursor keys

The following code creates a standard listbox in tkinter. In normal use, after the user makes the first listbox selection with a mouse click, subsequent selections can be made either by clicking again with the mouse, or by using the up/down cursor keys. Both of these (mouse click and cursor keys) correctly trigger ListboxSelect and change the value of SelectedIndex using the associated function UserClickedSelection(event).
The code also includes a function that allows me to set a listbox selection programmatically. This works perfectly, and correctly changes SelectedIndex using the SetSelection(index) function. But...and this is the problem...after making a selection programmatically, the up/down arrow keys no longer function. The user needs to make the next selection using the mouse, and then the up/down arrow keys once again function normally.
import tkinter as tk
root = tk.Tk()
root.geometry("300x300")
SelectedIndex = 0
def UserClickedSelection(event): # get user selection
global SelectedIndex
SelectedIndex = mylistbox.curselection()[0]
def SetSelection(index): # set selection
global SelectedIndex
mylistbox.selection_clear(0,tk.END)
mylistbox.selection_set(index)
mylistbox.activate(index)
SelectedIndex = mylistbox.curselection()[0]
mylistbox = tk.Listbox(root,activestyle="none")
mylistbox.place(x=0,y=0)
mylistbox.config(selectmode=tk.BROWSE)
mylistbox.config(exportselection=False)
mylistbox.bind('<<ListboxSelect>>',UserClickedSelection)
mylist = ['Zero','One','Two','Three','Four','Five']
mylistbox.insert(0,*mylist)
# Using function: set selection to index 2
SetSelection(2)
root.mainloop()
As you can see, in the code I've used the programmatic function to select index 2 of the listbox. This works fine, but the up/down arrow keys do not work until another selection is made afterwards using a mouse click. So there is clearly a difference between a "real" user selection and my "programmatic" selection. Is there some way to rectify this? I need the up/down arrow keys to work consistently. Thanks in advance for any assistance.
If I understand the problem correctly, you just need to make sure the listbox has focus.
def SetSelection(index): # set selection
...
mylistbox.focus_set()

AHK in MS Excel (Cell Selection Issue With Script)

I started a little script using CAPSLock key for navigation (This is only part of the code):
SetCapsLockState, AlwaysOff
CapsLock & i::
if getkeystate("alt") = 0
Send,{Up}
else
Send,+{Up}
return
CapsLock & l::
if getkeystate("alt") = 0
Send,{Right}
else
send, +{Right}
return
It works perfectly everywhere.. except in MS Excel!
When I select a range of cells the selection marquee is there but no cell reference is taken in the formula.
Ex: Summing C3:C10 turns into =sum() no cells are actually selected in the formula.
if I keep trying up and down many times.. it shows, but never consistent.
Any idea how to fix this?
Thank you in advance
The problem comes from your shift key being released between the key presses.
Like for example try pressing keys like this in Excel and you'll see you're not actually selecting cells, you're just highlighting them:
Shift Down, Up Arrow, Shift Up
Shift Down, Up Arrow, Shift Up
Shift Down, Up Arrow, Shift Up
...
So you're going to have to keep shift pressed for the whole duration of your selection making process.
Here's what I could come up with:
CapsLock::Shift
#If, GetKeyState("CapsLock", "P")
*i::
if (GetKeyState("Alt", "P"))
SendInput, {Blind}{Alt Up}{Up}
else
SendInput, {Up}
return
*l::
if (GetKeyState("Alt", "P"))
SendInput, {Blind}{Alt Up}{Right}
else
SendInput, {Down}
return
#If
Or just like this to write it a lot cleaner with a ternary:
CapsLock::Shift
#If, GetKeyState("CapsLock", "P")
*i::SendInput, % GetKeyState("Alt", "P") ? "{Blind}{Alt Up}{Up}" : "{Up}"
*l::SendInput, % GetKeyState("Alt", "P") ? "{Blind}{Alt Up}{Right}" : "{Right}"
#If
So what's happening?
First we use the simple remapping syntax(docs) to remap CapsLock to Shift.
Then we create context sensitive hotkeys for I and L with #If(docs).
The hotkeys are only triggered if the physical state of CapsLock is down.
We need the physical state, because the logical state (which is default) was remapped to shift.
The hotkeys are created with the * modifier(docs) so they fire even if Shift and/or Alt is held down.
I switched the Send commands SendInput due to it being the recommended faster and more reliable send mode(docs).
And then about {Blind}. Normally, when you just send something with a send command, it automatically releases any modifiers you may be holding. But if you use the blind send mode(docs), this doesn't happen. So Shift is still held down all the time.

TKinter - Clear text widget

I am inputting a random number from 1 to 25 into a text box on button press.
Every time i press the button, i want the text box to be emptied before the new number is stored - but putting self.outputbox.delete("1.0") into the button command only deletes the first character. i tried replacing 1.0 by something obvious like 2.0, but it never deleted both characters. At the moment, i am doing a very dirty solution by just calling self.outputbox.delete("1.0") twice - but i want to know how to delete the entire content of the text box.
this is the part:
def change_button_color(self):
randomcolor = self.get_random_color()
randombutton = self.random_button()
for z in range(0,1):
self.buttons['button{}'.format(randombutton)].config(bg=randomcolor)
for i in range(0,40):
self.outputbox.delete("1.0")
self.outputbox.insert("1.0","Button" + str(randombutton) + " " + "has the color" + " " + randomcolor)
as you can see, i currently have a rather dirty solution to clear the box
Do this
self.outputbox.delete("1.0", self.END)
it will clear all the text widget
And if you imported tkinter as tk do this
self.outputbox.delete("1.0", self.tk.END)

Delete a character from string realbasic

I have a virtual keyboard created in RealBasic.
When I press letters, numbers I append it to a textfield all its ok but, how do I delete characters from that textfield from current cursor position when I press "Delete" button from virtual keyboard?
To append letters or numbers to the textfields I use:
TextField1.Text = TextField1.text + me.Caption //to append caption
TextField1.SelStart = Len(TextField1.text) // to move cursor at the end of string
Paul's solution works if you only plan to delete the last typed character.
But beware: If you let the user also move the cursor left and right, you have to delete the text at the position of the cursor, of course. And if you also allow the user to select text, then it's even more complicated.
I suggest that your virtual keyboard simply send the typed key to the system as if the user had pressed the key. That way, the TextEdit field will do everything for you.
To make this work, however, you need custom solutions for each OS platform you want to support.
Let me know which platforms you plan to support and I'll see what I can find. I have some code for OSX but not for Windows, yet.
Doing what Thomas said means:
dim n as String = TextField1.Text
n = newText.left(TextField1.selStart) + n.right(n.len - textField1.selStart - 1)
textField1.text = n
Just lop off the last character:
TextField1.Text = TextField1.Text.Left(TextField1.Len-1)

Autohotkey remapping alt+j to left but alt+shift+j doesn't select left nor do alt+ctr+j move a caret , if getKeyState does not work

Basically,
It's inspired by Vim I want to use a key(e.g Alt, F1) combination(+I J K L) to map to Arrow Keys
What is already done in Autohotkey
Ralt & j::send{Left}
Ralt & k::send{Right}
...
Now I take Alt+I as up etc,which is pretty fine for me But the problem comes when you press
Ralt+Shift+j (Suppose to select the last charater)
Ralt+Ctrl+j (Suppose to move a caramel text)
These kind of combination would not work and it just get overrided to basic move cursor to left
Even if I use if/while statement with GetKeyState, it doesn't gonna work
if GetKeyState("Shift","P")
Ralt+j::send +{Left}
This kind of stuff didn't work
Any Ideas on that ?It would make coding very efficient without having to move the right hand.
Thanks in advance.
You are missing 2 things:
Must use a # symbol when doing a context sensitive hotkey
The bottom section of code is using a + instead of the & you used previously.
See the below modification:
RAlt & j:: Send {Left}
RAlt & k:: Send {Right}
#If GetKeyState("Shift","P")
RAlt & j:: Send +{Left}
RAlt & k:: Send +{Right}
; Close with #If to remove the context or simply start another '#If GetKeystate ....'

Resources