QT 创建可复用查找、替换对话框

目录

1、查找对话框的实现

2、Qt中的调色板(palette)

3、替换对话框的实现

目标: 开发一个可以在不同项目间复用的查找替换对话框 


1、查找对话框的实现

查找对话框需求分析

  -查找文本框中的指定字符串 

  -能够指定查找方向 

  -支持大小写敏感查找 

  -点击关闭按钮后隐藏 

查找对话框的界面布局 

   

查找对话框的架构与设计 

 

 

文本查找功能的核心思想 

      1. 获取当前光标的位置并作为起始点 

  - 文本框中的光标是一个QTextCursor对象 , 所有与光标相关的信息都通过QTextCursor描述 。 如:光标位置,文本选择,等等 

      2. 向后(向前)查找目标第一次出现的位置 

  - indexOf :从指定位置向后查找目标子串的下标位置 

  - lastIndexOf :从指定位置向前查找目标子串的下标位置 

      3. 通过目标位置以及目标长度在文本框中进行标记 

MainWindow与FindDialog之间的关系图 

  - MainWindow包含FindDialog 和 QPlainTextEdit (组合),FindDialog需要有一个QPlainTextEdit(通过指针)来查找内容(聚合)

 

FindDialog.h

#ifndef _FINDDIALOG_H_
#define _FINDDIALOG_H_

#include <QDialog>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QRadioButton>
#include <QCheckBox>
#include <QGroupBox>
#include <QPlainTextEdit>
#include <QPointer>

class FindDialog : public QDialog
{
    Q_OBJECT

protected:
    QGroupBox m_radioGrpBx;

    QGridLayout m_layout;
    QHBoxLayout m_hbLayout;

    QLabel m_findLbl;
    QLineEdit m_findEdit;
    QPushButton m_findBtn;
    QPushButton m_closeBtn;
    QCheckBox m_matchChkBx;
    QRadioButton m_forwardBtn;
    QRadioButton m_backwardBtn;

    QPointer<QPlainTextEdit> m_pText; // FindDialog 聚合使用 QPlainTextEdit

    void initControl();
    void connectSlot();
protected slots:
    void onFindClicked();
    void onCloseClicked();
public:
    explicit FindDialog(QWidget* parent = 0, QPlainTextEdit* pText = 0);
    void setPlainTextEdit(QPlainTextEdit* pText);
    QPlainTextEdit* getPlainTextEdit();
    bool event(QEvent* evt);  
};

#endif // _FINDDIALOG_H_

FindDialog.cpp

#include "FindDialog.h"
#include <QEvent>
#include <QTextCursor>
#include <QMessageBox>

FindDialog::FindDialog(QWidget *parent, QPlainTextEdit* pText)
    : QDialog(parent, Qt::WindowCloseButtonHint | Qt::Drawer)
{
    initControl();
    connectSlot();
    setLayout(&m_layout);
    setWindowTitle("Find");
    setPlainTextEdit(pText);
}

void FindDialog::initControl()
{
    m_findLbl.setText("Find What:");
    m_findBtn.setText("Find Next");
    m_closeBtn.setText("Close");
    m_matchChkBx.setText("Match Case");
    m_backwardBtn.setText("Backward");
    m_forwardBtn.setText("Forward");
    m_forwardBtn.setChecked(true);
    m_radioGrpBx.setTitle("Direction");

    m_hbLayout.addWidget(&m_forwardBtn);
    m_hbLayout.addWidget(&m_backwardBtn);

    m_radioGrpBx.setLayout(&m_hbLayout);

    m_layout.setSpacing(10);
    m_layout.addWidget(&m_findLbl, 0, 0);
    m_layout.addWidget(&m_findEdit, 0, 1);
    m_layout.addWidget(&m_findBtn, 0, 2);
    m_layout.addWidget(&m_matchChkBx, 1, 0);
    m_layout.addWidget(&m_radioGrpBx, 1, 1);
    m_layout.addWidget(&m_closeBtn, 1, 2);

}

void FindDialog::connectSlot()
{
    connect(&m_findBtn, SIGNAL(clicked()), this, SLOT(onFindClicked()));
    connect(&m_closeBtn, SIGNAL(clicked()), this, SLOT(onCloseClicked()));
}

void FindDialog::setPlainTextEdit(QPlainTextEdit* pText)
{
    m_pText = pText;
}

QPlainTextEdit* FindDialog::getPlainTextEdit()
{
    return m_pText;
}

bool FindDialog::event(QEvent* evt)
{
    if( evt->type() == QEvent::Close )
    {
        hide();

        return true;
    }

    return QDialog::event(evt);
}

void FindDialog::onFindClicked()
{
    QString target = m_findEdit.text();

    if( (m_pText != NULL) && (target != "") )
    {
        QString text = m_pText->toPlainText();
        QTextCursor c = m_pText->textCursor();
        int index = -1;

        if( m_forwardBtn.isChecked() )
        {
            index = text.indexOf(target, c.position(), m_matchChkBx.isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive);

            if( index >= 0 )
            {
                c.setPosition(index);
                c.setPosition(index + target.length(), QTextCursor::KeepAnchor);

                m_pText->setTextCursor(c);
            }
        }

        if( m_backwardBtn.isChecked() )
        {
            index = text.lastIndexOf(target, c.position() - text.length() - 1, m_matchChkBx.isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive);

            if( index >= 0 )
            {
                c.setPosition(index + target.length());
                c.setPosition(index, QTextCursor::KeepAnchor);

                m_pText->setTextCursor(c);
            }
        }

        if( index < 0 )
        {
            QMessageBox msg(this);

            msg.setWindowTitle("Find");
            msg.setText("Can not find \"" + target + "\" any more...");
            msg.setIcon(QMessageBox::Information);
            msg.setStandardButtons(QMessageBox::Ok);

            msg.exec();
        }
    }
}

void FindDialog::onCloseClicked()
{
    close();
}

使用该查找对话框类

MainWindow.h

QPlainTextEdit mainEditor; // mainEditor为文本编辑框对象
QSharedPointer<FindDialog> m_pFindDlg; // MainWindow 组合使用 FindDialog 和 QPlainTextEdit

MainWindowUI.cpp

MainWindow::MainWindow() : m_pFindDlg(new FindDialog(this, &mainEditor))
{
    
}

存在问题:查找式颜色没有高亮显示,不直观

 

2、Qt中的调色板(palette)

QPalette类包含了组件状态的颜色组 ,QPalette对象包含3个状态的颜色描述

      -激活颜色组(Active) :组件获得焦点使用的颜色搭配方案

      -非激活颜色组(Inactive) :组件失去焦点使用的颜色方案

      -失效颜色组(Disabled) :组件处于不可用状态使用的颜色方案 

QPalette::ColorGroup定义了组细节的颜色值 ,QPalette::ColorRole中的常量值用于标识组件细节 

enumColorGroup { Disabled, Active, Inactive, Normal }  细节查文档吧
enumColorRole { Window, Background, WindowText, Foreground, ..., NoRole }   

理解Qt中的调色板 

      -调色板是存储组件颜色信息的数据结构 ,组件外观所使用的颜色都定于调色板中 ,窗口组件内部都拥有QPalette对象 

      -重新设置组件调色板的值能够改变特定区域的颜色 ,QPalette对象是定制组件外观的重要角色 

Widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QPushButton>
#include <QLineEdit>
#include <QLabel>

class Widget : public QWidget
{
    Q_OBJECT

    QPushButton m_button;
    QLineEdit m_edit;
    QLabel m_label;
protected slots:
    void onButtonClicked();
    void onTextChange(const QString&);
public:
    Widget(QWidget *parent = 0);
    ~Widget();
};

#endif // WIDGET_H

Widget.cpp

#include "Widget.h"
#include <QPalette>
#include <QMessageBox>

Widget::Widget(QWidget *parent)
    : QWidget(parent), m_button(this), m_edit(this), m_label(this)
{
    m_label.move(10, 10);
    m_label.resize(150, 25);
    m_label.setText("Test");

    m_edit.move(10, 45);
    m_edit.resize(150, 25);

    m_button.move(10, 80);
    m_button.resize(150, 25);
    m_button.setText("Test");

    connect(&m_button, SIGNAL(clicked()), this, SLOT(onButtonClicked()));
    connect(&m_edit, SIGNAL(textEdited(const QString&)), this, SLOT(onTextChange(const QString&)));

    QPalette p = m_button.palette(); // 获取m_button的调色板

    p.setColor(QPalette::Active, QPalette::ButtonText, Qt::red);    // 设置激活时,按钮文本为红色
    p.setColor(QPalette::Inactive, QPalette::ButtonText, Qt::red);  // 设置非激活时,按钮文本为红色

    m_button.setPalette(p); // 给m_button设置调色板

    p = m_edit.palette();

    p.setColor(QPalette::Active, QPalette::Highlight, Qt::red);           // 高亮背景为红色
    p.setColor(QPalette::Active, QPalette::HighlightedText, Qt::white);   // 高亮文本为白色

    p.setColor(QPalette::Inactive, QPalette::Highlight, Qt::yellow);        // 高亮背景为黄色
    p.setColor(QPalette::Inactive, QPalette::HighlightedText, Qt::green);   // 高亮文本为白色

    m_edit.setPalette(p);
}

// 点击按钮更改m_label的调色板方案
void Widget::onButtonClicked()
{
    QPalette p = m_label.palette();

    p.setColor(QPalette::Active, QPalette::WindowText, Qt::green);
    p.setColor(QPalette::Inactive, QPalette::WindowText, Qt::green);

    m_label.setPalette(p);
}

void Widget::onTextChange(const QString&)
{
    if(m_edit.text().count() > 6)
    {
        m_edit.selectAll();
        QMessageBox::information(this, "tip", "字符超出限制", QMessageBox::Ok);
    }
}

Widget::~Widget()
{

}

查找对话框高亮显示的颜色问题

QPalette p = mainEditor.palette();

p.setColor(QPalette::Inactive, QPalette::Highlight, p.color(QPalette::Active, QPalette::Highlight));

p.setColor(QPalette::Inactive, QPalette::HighlightedText, p.color(QPalette::Active, QPalette::HighlightedText));

mainEditor.setPalette(p);

 

3、替换对话框的实现

替换对话框

                                 

替换对话框的设计与实现 

MainWindow与ReplaceDialog之间的关系图 

ReplaceDialog.h

#ifndef _REPLACEDIALOG_H_
#define _REPLACEDIALOG_H_

#include "FindDialog.h"

class ReplaceDialog : public FindDialog
{
    Q_OBJECT

protected:
    QLabel m_replaceLbl;
    QLineEdit m_replaceEdit;
    QPushButton m_replaceBtn;
    QPushButton m_replaceAllBtn;

    void initControl();
    void connectSlot();
protected slots:
    void onReplaceClicked();
    void onReplaceAllClicked();
public:
    explicit ReplaceDialog(QWidget *parent = 0, QPlainTextEdit* pText = 0);
};

#endif // _REPLACEDIALOG_H_

ReplaceDialog.cpp

#include "ReplaceDialog.h"

ReplaceDialog::ReplaceDialog(QWidget *parent,  QPlainTextEdit* pText) :
    FindDialog(parent, pText)
{
    initControl();
    connectSlot();
    setWindowTitle("Replace");
}

void ReplaceDialog::initControl() 
{
    m_replaceLbl.setText("Replace To:");
    m_replaceBtn.setText("Replace");
    m_replaceAllBtn.setText("Replace All");

    m_layout.removeWidget(&m_matchChkBx); // 父类的构造函数已经初始化,所以需要移除
    m_layout.removeWidget(&m_radioGrpBx);
    m_layout.removeWidget(&m_closeBtn);

    m_layout.addWidget(&m_replaceLbl, 1, 0);
    m_layout.addWidget(&m_replaceEdit, 1, 1);
    m_layout.addWidget(&m_replaceBtn, 1, 2);
    m_layout.addWidget(&m_matchChkBx, 2, 0);
    m_layout.addWidget(&m_radioGrpBx, 2, 1);
    m_layout.addWidget(&m_replaceAllBtn, 2, 2);
    m_layout.addWidget(&m_closeBtn, 3, 2);
}

void ReplaceDialog::connectSlot()
{
    connect(&m_replaceBtn, SIGNAL(clicked()), this, SLOT(onReplaceClicked()));
    connect(&m_replaceAllBtn, SIGNAL(clicked()), this, SLOT(onReplaceAllClicked()));
}

void ReplaceDialog::onReplaceClicked()
{
    QString target = m_findEdit.text();
    QString to = m_replaceEdit.text();

    if( (m_pText != NULL) && (target != "") && (to != "") )    
    {
        QString selText = m_pText->textCursor().selectedText();//第一次没有选择任何文本

        if( selText == target )
        {
            m_pText->insertPlainText(to);
        }

        onFindClicked();//第一次不会替换,会查找,符合Windows上的记事本替换准则
    }
}

void ReplaceDialog::onReplaceAllClicked()
{
    QString target = m_findEdit.text();
    QString to = m_replaceEdit.text();

    if( (m_pText != NULL) && (target != "") && (to != "") )
    {
        QString text = m_pText->toPlainText();

        text.replace(target, to, m_matchChkBx.isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive);

        m_pText->clear();

        m_pText->insertPlainText(text);
    }
}

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值