qt5 catch input from qtextedit - python

I am working on a small application which is basically a serial terminal with some added stuff.
for the terminal window I use the QTextEdit widget and allready overload add and overload some methods. However since this is a serial terminal I don't want the input that the user is typing in the QTextEdit to actually end up there. Most serial communication channels echo back the input that is send to them and I would like to show this in the QTextEdit and not what the user inputs.
The ideal would be I could overload the way QTextEdit handles its input and I work from there.
I have looked online but I can't seem to find what I am looking for. Maybe I am using the wrong search terms

You can set the QTextEdit widget to read-only mode and then just listen for its key events. That way nothing will be displayed in the QTextEdit and you will be able to intercept the keys.
If you subclass QTextEdit and reimplement the keyPressevent, you might want to call the base class implementation inside it. Otherwise you might not get the functionalities that for example page-up/page-down keys provide.

Related

How to use "on edit" events/signals with e.g. QLineEdit in pyside6 (Qt6)

Sorry for this post but I still don't get it after my research on the internet.
I am using Python PySide6 since I need to due to some display scaling issues I have with PyQt6 and other older versions.
I already have implemented the basics of a large program with dynamic .ui loading and now I want to implement the event actions for all my gui elements. Some I already managed to use by overloading the eventFilter method of the gui objects by using installEventFilter(self) function. That works well for hovering and other things and the used events are always of the type QtCore.QEvent. .... The problem is that I am missing some events here.
First an easy example and maybe the potential solution explains it for all other cases in my code:
How can I implement a function for the "on change" event of an QLineEdit object? I just want to get notified when the value of the control has been changed.
On the internet I find documentation for signals that should be connected to a slot that I can implement myself.
For example:
self.any_line_edit.textChanged.connect(self.any_slot)
The strange thing is, my QLineEdit object seems to have no reference for the "textChanged" signal. At least PyCharm is not able to resolve the name and I see the other methods of the QLineEdit class so the type of the object seems to be fine.
On other websites I find a similar example for QPushButton:
self.button.clicked.connect(self.the_button_was_clicked)
Same problem here. My PySide6 QPushButton seem to have no signal called "clicked".
Then I thought, no problem. Maybe I just continue using the eventFilter overload function and just install and replace the eventFilter for every object and manually filter the needed event myself.
But it seems that a simple QLineEdit throws no event that equals an "on edit" functionality.
I just see events like: QEvent::Paint, QEvent::DynamicPropertyChange, QEvent::WindowDeactivate, QEvent::Leave and many others but nothing like "on edit" or "edit end" or "on changed" or something.
So it seems that I don't see a respective event in the eventFilter function and due to any circumstance I also don't see the signals used to connect the Object to Slots.
I am sure I am missing something very basic but currently I am really confused.
I am using Python 3.9, PySide6 and PyCharm 2022.1 .
I just want to get notified if these input controls are getting changed in their values. I even have more complex signal-slot constructs and eventFilter reimplementations in my code and now I fail on such a basic thing. To my excuse: Normally I am implementing in Qt5 with C++ so I am a noob regarding Python and PySide6. xD
There is no such "on edit" event. The reason is that events are not meant for that. As the documentation explains:
In Qt, events are objects, derived from the abstract QEvent class, that represent things that have happened either within an application or as a result of outside activity that the application needs to know about. Events can be received and handled by any instance of a QObject subclass, but they are especially relevant to widgets.
So, events are "generic", not specialized for any widget or object type.
An "on edit" event would make sense only for editable widgets (which are just a few: QLineEdit, QPlainTextEdit, QTextEdit and their derived classes), and such an event would be also too generic and abstract to justify its existence.
Most importantly, events are normally created by Qt and then "sent" to the objects that could and possibly should handle them; again, from the above docs:
When an event occurs, Qt creates an event object to represent it by constructing an instance of the appropriate QEvent subclass, and delivers it to a particular instance of QObject (or one of its subclasses) by calling its event() function.
Note: some events are "synthetic", generated internally by Qt when required, sometimes even by widgets: in some cases, it's to work around some OS specific issues in complex focus situations, others due to the architecture of a particular framework (such as the Graphics View, which uses an internal "graphics event" system for items).
Qt cannot know (nor should) if the target object(s) is "editable". That's also because events are normally propagated from the target object up to the object tree, going up through all its parents, until the event is actually handled or (at least) accepted. That is of utmost importance for the event system: especially with input events, those events are intended for generic use by any object in the widget structure, so a widget (instance) specific "on edit" event wouldn't make any sense, mostly because it would be an event that would be only used by the widget itself.
In fact, some similar events do exist (such as QInputEvent, or the more specific QKeyEvent), but, as the name suggests, they are input events, they do not tell with certainty that the event actually results in an edit.
When the user presses a key, Qt creates a QKeyEvent and sends it to the currently focused widget. If that widget accepts that event, that event is (normally) not processed anymore by anything else. If the widget does not accept it, Qt will then propagate the event to its parent, which will decide if accept it in turn or not, and so on up to the top level window.
Note: events can be handled (or not) and accepted (or ignored). This means that a widget could handle (do "something" with that event) and still ignore it. A typical example is the Tab key: a QLineEdit would handle it in the sense that it will check that event, and then ignore it; then that event will be managed by its parent which possibly use it to switch the focus to the next widget that accepts it. A QTextEdit, instead, will both handle and accept the event, as it will normally write a tabulation character in the document contents.
In summary, an event is dispatched to a specific designated object and generally only handled by the single object that actually accepts it.
Signals, on the other hand, are a "communication system" that follows the observer pattern, similarly to the callback mechanism: you "subscribe" to a certain signal and whenever the object emits that signal, the receiver will do anything it wants. The eventual argument(s) of that signal is not changed (or, at least, it shouldn't), and the subscriber(s) can be anything. The sender of that signals doesn't need to care about the targets, nor the different "hierarchy" of those objects matters, as opposed to events.
In summary, don't use events for this, use signals, as that's what they've been made for. This is completely fine:
self.any_line_edit.textChanged.connect(self.any_slot)
Finally, the warnings you're getting from PyCharm are just that: warnings (which are not errors). When the UI is dynamically loaded on runtime, the IDE cannot know the object types of the new attributes, because they will be effective only when the program is running.
In fact, the object to which the attribute is referencing could also change during the lifespan of the program: imagine a class that sets an instance attribute for a "target" widget that is used as an argument in its __init__. How could the IDE know if that widget is a QLineEdit or a QPushButton and "accept" the attributes of that specific widget, such as textChanged or clicked? It couldn't.
So, dynamically created attributes will always show that warning; and you can safely ignore them, as annoying as they are (there should be some shortcut to do that, AFAIK).

QPlainTextEdit checking some condition

I want to create my own very simple editor of .txt files. As in real editors, I want that if you change the file and don't save it yet, the name of file will start with '*' (for example, *some_text_file.txt).
I think that fot this I should check QPlainTextEdit after the file was downloaded to editor and after the user pushed button 'save'. But I don't know how to check QPlainTextEdit without user control, but after some changes. Or maybe there is another way to do it. So, how to do it?
You could use the textChanged signal from the QPlainTextEdit. It indicates when the input text has changed. See:
https://doc.qt.io/qt-5/qplaintextedit.html#textChanged
Roughly, you would do the following:
load the file
display the filename without asterisk
connect the textChanged signal into a slot (function) that will add asterisk to the filename
when the Save button is pressed, remove the asterisk
If you're a Qt beginner, you might want to read about the Qt signal and slot mechanism:
https://doc.qt.io/qt-5/signalsandslots.html

Access the built-in shortcuts of PyQt5 components?

I'm very keen on being able to use the keyboard to do everything with a GUI and am currently exploring QTreeView and QTableView among other things.
I'm adding a lot of my own hotkeys (shortcuts) and am devising a method to automate a user list or guide to these available hotkeys.
But something like QTreeView also comes with its own built-in hotkeys, e.g. arrow keys for navigation, F2 to start editing, Ctrl-A for "select all", etc.. I want to get a comprehensive list of these and include them in the automatically generated user guide.
I've got to this page, for example, but I haven't really got a clue how to dig down into PyQt5 components to unearth this kind of information programmatically.
There's some interesting functionality, probably unknown to many users, with QTreeView: e.g. if, in column 0, you have a tree structure you can skip from label (text) to label by pressing the first letter of each one's label. But if you enter 2 (or more) keys quickly enough this also works: entering "ra" will skip over "Roma" and "Rimini" to "Ravenna" even if "Roma" and "Rimini" come first. It turns out that this is implemented by QTreeView.keyboardSearch ... but what I want to know is whether it's possible to find details of the "mapping" functionality for this and other keyboard enablements, often implemented by keyPressEvent, programmatically. Having looked a little at the PyQt5 files it seems that a lot of PyQt5 functionality may ultimately be contained in .dll files (this is a W10 machine), so I'm not particularly optimistic.
Each widget has a certain behavior depending on the hotkeys pressed, so there is no documentation that indicates all the cases, so you will have to review the documentation of each class and the parent class. So for example to understand the behavior of QTableView you should also review the documentation of QAbstractItemView, QAbstractScrollArea and QFrame (the same is for QTreeView), considering the above we can collect information:
void QAbstractScrollArea::keyPressEvent(QKeyEvent *e)
This function is called with key event e when key presses occur. It
handles PageUp, PageDown, Up, Down, Left, and Right, and ignores all
other key presses.
QAbstractItemView:
void QAbstractItemView::keyPressEvent(QKeyEvent *event).
This function is called with the given event when a key event is sent
to the widget. The default implementation handles basic cursor
movement, e.g. Up, Down, Left, Right, Home, PageUp, and PageDown; the
activated() signal is emitted if the current index is valid and the
activation key is pressed (e.g. Enter or Return, depending on the
platform). This function is where editing is initiated by key press,
e.g. if F2 is pressed.
(emphasis mine)
QTableView and QTreeView when inheriting from QAbstractItemView have the same hotkeys.

PySide text in QLineEdit not editable

I making a console like program for my application. I have a QLineEdit that takes up the whole height of the screen, where the user will be able to input the commands. I want to add "prompts" for instance 'hostname:current_dir># ' after the # the user will put the command. I want that prompt to NOT be editable (he can just backspace it away) but still have the user be able to type commands. Any ideas? Or may someone suggest a better way of doing this please?
You could connect a slot to the cursorPositionChanged () signal, check its position, and disable editing with setEnabled(False). You might also want to take a look into QTextEdit, QTextBrowser or QPlainTextEdit, where you could use the setReadOnly method.

What signal can be connected to an initial dialog display in pyqt4 (qt)

I have an application in which I would like to connect whatever signal is emitted when a pyqt4 dialog is displayed in order to do execute an initial method. I don't want the method to be called in the __init__ method for a number of reasons. I've spent quite some time searching but I have yet to find an answer. I'm sure there is a simple solution that because of my inexperience I am overlooking as I can do this in wxPython. Suggestions?
There is no signal emitted on first display, instead, you will have to intercept the first resizeEvent or paintEvent by overloading these methods (as you don't want to initialize from the __init__ method).
Another option would be to add your own showAndInit method, that initializes and then calls show.

Categories