QLineEdit实现“命令提示符”效果
又是n久木有更新…罪过罪过…
今天讲个在做项目过程中遇到的问题。大家应该都知道Windows的Console或者*nix里面的终端,在里面输入命令的时候,每行前面都会有一个“提示符”,如:
PS F:\> ls
ls命令左侧的部分就是提示符,它是一直存在且用户无法更改的。
在QT里面想实现一个带提示符的单行命令输入组件该怎么做呢?
提到单行命令输入组件,最容易想到的是QLineEdit,但是QLineEdit不像QSpinBox一样提供设置Prefix和Suffix的功能,那就只好自己改造一下QLineEdit了。
大体的思想是这样的:在QLineEdit中加一个字符串保存“命令提示符”,与用户输入的字符串连接后组成显示文本。当用户输入、删除、选择文本时,均不能对QLineEdit中显示的“命令提示符”字符串进行操作。需要注意的是,在QLineEdit中,如果用户选中了某段文本,然后再按键盘输入内容,那么选中的文本会被输入的内容替换掉。
具体实现也很简单,过程如下:
1. 从QLineEdit继承一个类,名字就叫CommandEdit好了,添加一个QString属性用于保存提示符。
2. 重载setText函数,在用户设置文本时,将用户设置的文本缀在“提示符”后面作为组件的文本。
3. 重载mousePressEvent、mouseMoveEvent、mouseDoubleClickEvent、keyPressEvent、contextMenuEvent.为什么要重载这些函数应该很明显的吧?
- mousePressEvent:防止用户点击“提示符”时cursor会移动到“提示符”部分。
- mouseMoveEvent:防止用户用鼠标拖拽选择时选中“提示符”部分的文本。
- mouseDoubleClickEvent:防止用户双击文本输入框时选中输入框中显示的全部文本。
- contextMenuEvent:QLineEdit的右键菜单中有一项叫“Select All”,我们得废掉它。我干的比较绝,直接不让右键菜单出来~
- keyPressEvent:这个就比较多了。
(1)首先是键盘的左方向键和Backspace有可能会让cursor移动到“提示符”部分。
(2)然后是上面说到的那个“Select All”的问题,它有个对应的快捷键是Ctrl + A,我们也得修改下它的作用。
(3)再就是Home键的功能,这个是很容易被忽略的。我们可以选择对Home键按下不做响应,简单快捷~~若想组件稍微好用点的,还是自己实现下Home键按下时的功能,也不过几行代码。按Home键的时候,将Cursor移动到“提示符”后面的位置,也就是用户可输入的起始位置。Shift + Home 同时按下时则是选中从“提示符”后面一直到当前cursor部分的文本。
上个图:
代码就直接贴出来好了~
Download commandedit.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #ifndef COMMANDEDIT_H #define COMMANDEDIT_H #include <qlineEdit> class CommandEdit : public QLineEdit { Q_OBJECT public: CommandEdit(const QString & prompt, QWidget * parent = 0); ~CommandEdit(); QString getPrompt() const; void setPrompt(QString prompt); protected: void keyPressEvent(QKeyEvent *event); void mousePressEvent(QMouseEvent* e); void mouseMoveEvent(QMouseEvent * e); void mouseDoubleClickEvent(QMouseEvent* e); void contextMenuEvent(QContextMenuEvent * e); public slots: void setText ( const QString & txt); private: QString cmdPrompt; }; #endif // COMMANDEDIT_H |
Download commandedit.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | #include "commandedit.h" #include <qkeyEvent> #include <qmouseEvent> CommandEdit::CommandEdit(const QString & prompt, QWidget * parent) : QLineEdit(prompt, parent) { cmdPrompt = prompt; } CommandEdit::~CommandEdit() { } void CommandEdit::mousePressEvent(QMouseEvent* e) { int curPos = cursorPositionAt (e->pos()); if (curPos < cmdPrompt.length()) { //Mouse clicked at command prompt area, do nothing } else { QLineEdit::mousePressEvent(e); } } void CommandEdit::mouseMoveEvent( QMouseEvent* e ) { int curPos = cursorPositionAt (e->pos()); if (curPos < cmdPrompt.length()) { //Mouse clicked at command prompt area, do nothing } else { QLineEdit::mouseMoveEvent(e); } } void CommandEdit::mouseDoubleClickEvent(QMouseEvent* e) { int curPos = cursorPositionAt (e->pos()); if (curPos < cmdPrompt.length()) { //Mouse clicked at command prompt area, do nothing } else { QLineEdit::mousePressEvent(e); } } void CommandEdit::keyPressEvent( QKeyEvent *event ) { if (cursorPosition() <= cmdPrompt.length() && (event->key() == Qt::Key_Left || event->key() == Qt::Key_Backspace)) { //Do nothing } else if (event->key() == Qt::Key_Home) { if (event->modifiers() == Qt::ShiftModifier) { setSelection(cmdPrompt.length(), cursorPosition()); } else { setCursorPosition(cmdPrompt.length()); } } else if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_A) { setSelection(cmdPrompt.length(), text().size()); } else QLineEdit::keyPressEvent(event); } void CommandEdit::contextMenuEvent( QContextMenuEvent* e) { //Do nothing } void CommandEdit::setText( const QString & txt ) { QLineEdit::setText(cmdPrompt + txt); setCursorPosition(cmdPrompt.length()); } void CommandEdit::setPrompt( QString prompt ) { cmdPrompt = prompt; setText(""); } |

我一点也没看懂,技术性太强、、、
今天晚上要是有空就发个木有技术性的……
我想知道的是… 如何再ui里面讲用到的LineEdit变成你重写的CommandEdit 是用promote to 这个方法吗? 将新写的类添加进去 可是编译的时候会有错误啊…
怎么做呢?
如果要在Designer里面用的话是要用Promote to,不过要修改CommandEdit的构造函数,要么加一个CommandEdit(QWidget * parent)这样的构造函数,要么把原来的构造函数改成CommandEdit(QWidget * parent, const QString & prompt = “Command>”);
(因为Designer在生成的代码里是用第一种形式new出CommandEdit,所以需要一个这样的构造函数)