I'm trying to create an Undo and Redo Button inside a GUI App using PyQt5 and Python 3.7.
When the Undo and Redo Buttons are clicked, the Key Sequences "Ctrl+Z" and "Ctrl+Y" should be executed respectively. Ive superficially gone through the documentation of QShortCut and QKeySequence but they seem to be designed for detecting key sequences and not triggering them. So how do I implement these buttons?
As per eyllanesc's comment, I'm adding this to better explain what I am trying to achieve.
self.undoButton = self.findChild(QtWidgets.QPushButton, 'undoButton')
self.undoButton.clicked.connect(self.undoButtonPressed)
self.anyPlainTextEdit = self.findChild(QtWidgets.QPlainTextEdit, 'anyPlainTextEdit')
# Function to Execute Key Sequence
def undoButtonPressed(self):
# Execute Ctrl+Z Key Sequence
I'm wondering if this is even possible.
If not, should I maintain Previous and current values of the PlainTextArea in separate variables and set the value of the PlainTextArea accordingly?
You don't have to launch the shortcut to enable redo or undo, just call the slot redo() and undo() when the buttons are pressed:
self.undoButton.clicked.connect(self.anyPlainTextEdit.undo)
self.redoButton.clicked.connect(self.anyPlainTextEdit.redo)
Related
I have an element, editorBox which is of the PyQt5 element type QPlainTextEdit. My target goal is to call a function when the hotkey Shift + Return is pressed, and my goal with this function is that it will also insert text into the editorBox element (this isn't the part I'm stressed about, it's fairly easy to do with the .insertPlainText() method).
I've done searching, and the closest result I could find was to use QShortcut & QKeySequence paired together like so:
# Initialize the QShortcut class
self.keybindShiftEnter = QShortcut(QKeySequence("Shift+Return"), self)
# Connect the shortcut event to a lambda which executes my function
self.keybindShiftEnter.activated.connect(lambda: self.editorBox.insertPlainText("my text to insert"))
For clarification, I have tried using other characters in the QKeySequence constructor, such as Ctrl+b, and I've had success with it. Oddly enough, only the combination Shift+Return doesn't work for me.
I've analyzed a problem with it in relation to my bug. Some of the posts I've viewed:
This is for triggering a button, not a QPlainTextEdit.
Best thing I've tried, almost worked up until I tried Shift+Return
Any solution with keyPressEvent wouldn't work, because keys other than Shift+Enter wouldn't be typed into the editorBox
Solved my own problem:
# ... editorBox Initialization code ...
self.editorBox.installEventFilter(self)
# Within App class
def eventFilter(self, obj, event):
if obj is self.editorBox and event.type() == QEvent.KeyPress:
if isKeyPressed("return") and isKeyPressed("shift"):
self.editorBox.insertPlainText("my text to insert")
return True
return super(App, self).eventFilter(obj, event)
What I'm doing here is setting a filter function- basically, every time a key is pressed (any key, including space/backspace/etc) it will call the eventFilter function. The first if statement makes sure that the filter will only pass through if it is a key stroke (not entirely sure if this part is necessary, I don't think clicks trigger the function). Afterwards, I utilize the isKeyPressed function (a renamed version of the keyboard module's is_pressed function) to detect if the current key is held down. With the and operator, I can use this to make keybind combos.
In short, i try to type letters (in input components like "Entry", "Text") that are allowed by Windows language-keyboard (i'm using "Latvan(QWERTY)" keyboard) and i can't write long letters like 'ā', 'č', 'ģ' and others.
For example, when i try to write 'ā', the result is 'â'.
The interesting part - when i focus on specific GUI input fiend and change Windows keyboard-language (with "Alt+Shift" shortcut or manually) twice (for example, from "Latvan(QWERTY)" to "Russian" and back to "Latvan(QWERTY)") - then i can write all letters i needed.
What i want is to set all input fields keyboard-language so i could write all letters i want without doing things mentioned above every time i launch my GUI program.
If you need more info or there is already place where this question is answered, please leave a comment and i will act accordingly.
Edit 1:
I am using PyCharm to write my Python Tkinter code. I tried to assign necessary keyboard to my program's generated GUI form according to this guide but it didn't work (i guess that because i used it on temporary created GUI forms).
I was able to solve my problem by using pynput.
Here is simplified version of my final code:
from tkinter import *
from pynput.keyboard import Key, Controller
def change_keyboard_lang(event):
keyboard = Controller()
for i in range(2):
keyboard.press(Key.alt)
keyboard.press(Key.shift_l)
keyboard.release(Key.shift_l)
keyboard.release(Key.alt)
root = Tk()
word_input = Entry(root)
word_input.focus_set()
word_input.bind("<FocusIn>", change_keyboard_lang)
word_input.pack()
root.mainloop()
In short, if cursor is focused on Entry field "word_input", system calls function "change_keyboard_lang" that changes input language from original to other and back to original - and now i can write necessary letters.
It's not the best solution since i need to bind event to every input field in my GUI form but it gets the job done. If you have a better solution please post it here.
I have a problem with this piece of code.
projList is a variable of type list. self.projPicker is an instance of QComboBox.
self.projPicker.addItems(projList)
self.projPicker.currentTextChanged.connect(self.itemListChange)
def itemListChange(self,value):
self.projPathLbl.setText("Project : " + value)
def itemListUpdate(self):
comboItems = []
for item in range (self.projPicker.count()):
comboItems.append(self.projPicker.itemText(item))
print(comboItems)
With this code, when I add text in in the combobox the self.projPathLbl is updated with the itemListChange() function each time I type a character .
My problem is, it doesn't work the same way with the itemListUpdate().
With this function, I need to hit the Return key to the update to be effective.
How can I update my self.projPathLbl label the same way I update my comboItems list ( validating it with the Return key )?
Maybe one way to do that would be to implement QComboBox as a custom class with an implemented keypress event like here: PyQt Connect to KeyPressEvent
In the keypress implementation you can filter the enter key and emit your signal, which you can connect to the itemListChange slot.
I have a Dialog Window with a TreeView and two Buttons (Gtk.ResponseType.CANCEL and Gtk.ResponseType.ACCEPT). I can't find how to activates the ResponseType.ACCEPT button when I press Enter inside the Gtk.TreeView. I set cant_datault on desired button and set_default on GtkDialog but Gtk.TreeView doesn't have an activates default method.
Is there any way I can do this?
The quickest way I could find would be to use the "row-activated" signal within the TreeView. This is activated whenever you press Enter, double-click an item or press the Spacebar.
So for example:
treeview.connect("row-activated", lambda a, b, c: dialog.response(Gtk.ResponseType.ACCEPT))
I've used lambda to create the anonymous function, but if you have anything else that needs to run at the same time, you can swap it for a proper function.
Just be aware that if you also change your default response in the future, you'll need to update this function as well.
I know this question is long but what I really want to know is in bold.
I would prefer to use python on Linux.
I'm trying to make a new keyboard layout kind of like devorak but the layout is set to either layout1 or layout2 depending on if you are holding a hot key or not (the hot key should probably be ctrl?)
e.g. press d -> "z" prints to the screen using key layout1
e.g. press ctrl d -> "x" prints to the screen using key layout2
My main problem (and question that needs answering) is the way characters need to print to the screen.
if someone presses the keys (in this order) "(a)(b)(c)(d)(ctrl+d)(shift+e=E)(f)(Enter)"
now lets say the output for these key presses should be "oijzxKb"
I don't want output to render with new lines:
o
i
j
z
x
K
b
I want the characters to appear instantly on the screen as each character is pressed (without waiting for them to press enter).
e.g.
press o
Screenshot1 o
press i
Screenshot2 oi
press j
Screenshot3 oij
.. etc
I assume I will need the following:
a way to read keypresses instantly
a way to print key presses instantly (to the terminal or a GUI or whatever is easiest initially, if it worked on any editor that would be cool!)
I could probably do this in PyGame (but then I probably wouldn't be able to cut and paste etc) and I'm guessing there should be an easier way.
I'm using a Logitech G110 keyboard, I may eventually want to use this as an alternative to my qwerty keyboard on all my applications across all my devices.
Thanks!
EDIT: SOLUTION:
Thanks to the first response,
using Getch from http://code.activestate.com/recipes/134892/
getch = _Getch()
word=""
while True:
c=getch.impl()
if c=="a":
word+="z"
elif ord(c)==127: #backspace
word=word[:-1]
else:
word+=c
print word
This will suffice for now thank you. Once I'm happy with refinement I'll look at doing something lower level, operating system specific without python.
One problem with getch however is that ctrl+a cant be distinguished between ctrl+A (e.g. if you hold ctrl and press keys, it can't tell the difference between upper and lower case)
If it's ok to depends on the X window system, you can use the python-xlib module or the xpyb module to access the X window system and use a XGrabKey call to grab the keyboard related events. Upon each KeyPress event you will be able to print the pressed key.
Now, if you really want to write a keymap, this is totally OS/window system dependent. If you use the X window system (Ubuntu does), you need to check the X documentation about how to write a new keymap. On Ubuntu, the current keymaps definition should be in /usr/share/X11/xkb. Take a look, and try to copy and edit one. You can use setxkbmap to change the current keymap then.
To modify the key mapping of your keyboard, you must use the tools provided by your OS. Most applications don't accept generated events for security reasons.
In your case, that would be xmodmap. Don't forget to create a backup of your current keymap using the -pke option because you will make a mistake - and then, your keyboard won't be working anymore.
If you also want your new keymap work on the console, have a look at the kbd package which changes the keyboard layout at the kernel level.