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
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("");
}

    • Lee
    • 2010年07月6日 23:19

    我一点也没看懂,技术性太强、、、

    • 今天晚上要是有空就发个木有技术性的……

    • Queen Marry
    • 2011年01月13日 14:46

    我想知道的是… 如何再ui里面讲用到的LineEdit变成你重写的CommandEdit 是用promote to 这个方法吗? 将新写的类添加进去 可是编译的时候会有错误啊…

    怎么做呢?

      • 飘流
      • 2011年01月14日 11:12

      如果要在Designer里面用的话是要用Promote to,不过要修改CommandEdit的构造函数,要么加一个CommandEdit(QWidget * parent)这样的构造函数,要么把原来的构造函数改成CommandEdit(QWidget * parent, const QString & prompt = “Command>”);
      (因为Designer在生成的代码里是用第一种形式new出CommandEdit,所以需要一个这样的构造函数)

  1. 没有通告

:wink: :-| :-x :twisted: :) 8-O :( :roll: :-P :oops: :-o :mrgreen: :lol: :idea: :-D :evil: :cry: 8) :arrow: :-? :?: :!:
  • move
  • close
use smiles

无觅相关文章插件,快速提升流量