一步步打造无frame的Qt自定义界面

一步步打造无frame的Qt自定义界面

标签(空格分隔): Qt frameless 无边框


Qt的一大优势就是QSS样式表,不过在用的时候界面还是有些不太舒服的地方,比如丑陋的标题栏。这里记录下改造Qt界面的步骤。

平台

Qt5.7.0 Dialog空白工程

无边框化

既然标题栏很丑,那么就直接去掉算了。

    setWindowFlags( Qt::FramelessWindowHint );

拖动和缩放

无边框之后会造成新问题–界面拖动不了,而且本来可以缩放的界面也不能拖动缩放了。解决方法很多,对我等小白来说最简单的是用第三方类NcFramelessHelper,3句代码就可以完美解决问题。下载链接最后附上。

    #include "NcFramelessHelper.h"
//.....
    Dialog w;//
    w.setWindowFlags( Qt::FramelessWindowHint );
    NcFramelessHelper* fh = new NcFramelessHelper;
    fh->activateOn(&w);

效果是这样的

标题栏

取消了默认的标题栏不代表不需要标题栏,为了实现较为时髦的标题栏,可以从QWidgets派生一个,再添加到界面上去。
这里继续用第三方类State_Button

    State_Button* minBtn = new State_Button(this);
    minBtn->set_pixmap(QPixmap(":/min.png"));
    State_Button* maxBtn = new State_Button(this);
    maxBtn->set_pixmap(QPixmap(":/max.png"));
    State_Button* clostBtn = new State_Button(this);
    clostBtn->set_pixmap(QPixmap(":/close.png"));



    QHBoxLayout* btnGroupLayout = new QHBoxLayout;
    QHBoxLayout* titleLayout = new QHBoxLayout;

    btnGroupLayout->addWidget(minBtn, 0, Qt::AlignTop);
    btnGroupLayout->addWidget(maxBtn, 0, Qt::AlignTop);
    btnGroupLayout->addWidget(clostBtn, 0, Qt::AlignTop);

    titleLayout->addLayout(btnGroupLayout);

    setLayout(titleLayout);

效果是这样的

和普通标题栏有点像了,但位置还不对,另外还缺少左侧的icon、对话框标题,下面一个个加进去。
修改如下代码

    QLabel*icon = new QLabel();
    icon->setPixmap(QPixmap(":/icon.png"));
    icon->setFixedSize(16, 16);
    icon->setScaledContents(true);

    QLabel*title = new QLabel("这是标题栏文字");

    State_Button* minBtn = new State_Button(this);
    minBtn->set_pixmap(QPixmap(":/min.png"));
    State_Button* maxBtn = new State_Button(this);
    maxBtn->set_pixmap(QPixmap(":/max.png"));
    State_Button* clostBtn = new State_Button(this);
    clostBtn->set_pixmap(QPixmap(":/close.png"));

    QHBoxLayout* titleLayout = new QHBoxLayout;

    titleLayout->addWidget(icon, 0, Qt::AlignTop);
    titleLayout->addSpacing(5);

    titleLayout->addWidget(title, 0, Qt::AlignTop);
    titleLayout->addStretch();
    titleLayout->addWidget(minBtn, 0, Qt::AlignTop);
    titleLayout->addWidget(maxBtn, 0, Qt::AlignTop);
    titleLayout->addWidget(clostBtn, 0, Qt::AlignTop);

    setLayout(titleLayout);

运行效果是这样

到这里标题栏样式就差不多了,但没有按钮点击事件啊,继续添加代码,同时按照C++封装的思想,将标题栏封装成类。代码如下

//无边框界面标题栏类
class Title_Bar: public QWidget
{
    Q_OBJECT
public:
    Title_Bar(QWidget *parent = NULL);
    ~Title_Bar();

    QString get_text(){return title->text();}
    void set_text(const QString& text){title->setText(text);}
    bool is_window_maximized() const {return is_maxed;}
protected:
    void init();
private slots:
    void show_small();
    void show_max_restore();
    void close_window();

protected:
    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void mouseDoubleClickEvent(QMouseEvent *event);

private:
    QHBoxLayout*    titleLayout;
    QLabel*         icon;
    QLabel*         title;
    State_Button*   menu_button;
    State_Button*   min_button;
    State_Button*   max_button;
    State_Button*   close_button;
    QRect           normal_rect;
    QPoint          click_pos;      //
    bool            left_pressed;   //left mouse pressed
    bool            is_maxed;       //window Maximized
};

Title_Bar::Title_Bar( QWidget* parent )
    :QWidget(parent)
    ,left_pressed(false)
    ,is_maxed(false)
{
    titleLayout     = new QHBoxLayout(this);

    icon            = new QLabel(this);
    title           = new QLabel(this);

    menu_button     = new State_Button(this);
    min_button      = new State_Button(this);
    max_button      = new State_Button(this);
    close_button    = new State_Button(this);

    //设置name以方便使用 CSS
    icon->setObjectName("title_bar_icon");
    title->setObjectName("title_bar_text");

    menu_button->setObjectName("title_bar_menu");
    min_button->setObjectName("title_bar_min");
    max_button->setObjectName("title_bar_max");
    close_button->setObjectName("title_bar_close");

    init();
}

Title_Bar::~Title_Bar()
{
}


void Title_Bar::init()
{
    //标题栏
    title->setText("这是标题栏");

    // 标题栏高度
    int titlebar_height = style()->pixelMetric(QStyle::PM_TitleBarHeight);
    setFixedHeight(titlebar_height);

    const int frame_width = 5;

    //layout
    titleLayout->addWidget(icon, 0, Qt::AlignVCenter);
    titleLayout->addSpacing(frame_width);
    titleLayout->addWidget(title, 0, Qt::AlignVCenter);
    titleLayout->addStretch();
    titleLayout->addWidget(menu_button, 0, Qt::AlignTop);
    titleLayout->addWidget(min_button, 0, Qt::AlignTop);
    titleLayout->addWidget(max_button, 0, Qt::AlignTop);
    titleLayout->addWidget(close_button, 0, Qt::AlignTop);

    titleLayout->setSpacing(1);
    titleLayout->setMargin(1);

    //icon
    icon->setPixmap(QPixmap(":/icon.png"));
    icon->setFixedSize(16, 16);
    icon->setScaledContents(true);


    //windows taskbar icon
    window()->setWindowIcon(QPixmap(":/icon.png"));
    //
    menu_button->set_pixmap(QPixmap(":/menu.png"));
    min_button->set_pixmap(QPixmap(":/min.png"));
    max_button->set_pixmap(QPixmap(":/max.png"));
    close_button->set_pixmap(QPixmap(":/close.png"));

    //
    setLayout(titleLayout);

    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);

    //
    connect(min_button, SIGNAL(clicked()), this, SLOT(show_small()));
    connect(max_button, SIGNAL(clicked()), this, SLOT(show_max_restore()));
    connect(close_button, SIGNAL(clicked()), this, SLOT(close_window()));

}

void Title_Bar::show_max_restore()
{
    if (is_maxed)
    {
        is_maxed = false;
        window()->setGeometry(normal_rect);
        max_button->set_pixmap(QPixmap(":/max.png"));
    } else {
        is_maxed = true;
        normal_rect = window()->geometry();
        window()->setGeometry(QApplication::desktop()->availableGeometry());
        max_button->set_pixmap(QPixmap(":/restore.png"));
    }
}

void Title_Bar::mousePressEvent( QMouseEvent *e )
{
    QRect r = rect();
    r.adjust(5, 5, -5, -5);
    if (r.contains(e->pos()))   //5:边框大小,边框用来拉伸改变窗口大小
    {
        if (e->button() == Qt::LeftButton)
        {
            left_pressed = true;
            click_pos = mapToParent(e->pos());
            e->accept();
            return;
        }
    }

    e->ignore();
}

void Title_Bar::mouseMoveEvent( QMouseEvent *e )
{
    if (left_pressed && !is_maxed)
    {
        window()->move(e->globalPos() - click_pos);
        e->accept();
    }else{
        e->ignore();
    }
}

void Title_Bar::mouseReleaseEvent( QMouseEvent *e )
{
    left_pressed = false;
    e->ignore();
}

void Title_Bar::show_small()
{
    window()->showMinimized();
}
void Title_Bar::close_window()
{
    window()->close();
}
void Title_Bar::mouseDoubleClickEvent( QMouseEvent *e )
{
    show_max_restore();
    left_pressed = false;
}

效果如图,最小化、最大化、关闭、菜单、双击标题栏最大化最小化都可以实现

主题

下面继续美化,终于可以祭出Qt的大绝招–QSS了。还是从网上找到的资源。添加到项目里去

    QFile file(":/dark.qss");
    file.open(QFile::ReadOnly | QFile::Text);
    QTextStream stream(&file);
    setStyleSheet(stream.readAll());

好了,初步的美化就有了。

加几个Qss美化的控件吧。

    QGridLayout* gridLayout = new QGridLayout;
    gridLayout->setMargin(10);

    QLabel* label = new QLabel("sdf");
    label->setFont(QFont("微软雅黑",12));
    gridLayout->addWidget(label,0,0);

    QPushButton* btn = new QPushButton("sdf");
    btn->setFont(QFont("微软雅黑",12));
    gridLayout->addWidget(btn,0,1);

    QCheckBox* check = new QCheckBox("615651651");
    check->setFont(QFont("微软雅黑",12));
    check->setChecked(true);
    gridLayout->addWidget(check,0,2);

    QComboBox* combo = new QComboBox;
    combo->setFont(QFont("微软雅黑",12));
    combo->addItem("sfsfsd");
    combo->addItem("234234");
    combo->addItem("78678");
    gridLayout->addWidget(combo,0,3);

    QLineEdit* line = new QLineEdit;
    line->setFont(QFont("微软雅黑",12));
    line->setText("LineText");
    gridLayout->addWidget(line,0,4);

    QListWidget *listWidget = new QListWidget(this);
    listWidget->setFont(QFont("微软雅黑",12));

    listWidget->insertItem(0,"列表1");
    listWidget->insertItem(1,"列表2");
    listWidget->insertItem(2,"列表3");
    listWidget->insertItem(3,"列表4");
    listWidget->insertItem(4,"列表5");
    listWidget->setAlternatingRowColors(true);
    gridLayout->addWidget(listWidget,1,0,2,2);

    QGroupBox *groupBox = new QGroupBox(tr("按钮组"));

    QRadioButton *radio1 = new QRadioButton(tr("&Radio button 1"));
    QRadioButton *radio2 = new QRadioButton(tr("R&adio button 2"));
    QRadioButton *radio3 = new QRadioButton(tr("Ra&dio button 3"));

    radio1->setChecked(true);
    QVBoxLayout *vbox = new QVBoxLayout;
    vbox->addWidget(radio1);
    vbox->addWidget(radio2);
    vbox->addWidget(radio3);
    vbox->addStretch(1);
    groupBox->setLayout(vbox);
    gridLayout->addWidget(groupBox,1,2,3,1);

    QTableWidget *table = new QTableWidget(3,2);
    table->setFont(QFont("微软雅黑",12));
    table->setAlternatingRowColors(true);
    table->setWindowTitle("VIP List");
    QStringList headerList;
    headerList << "No." << "姓名" ;
    table->setHorizontalHeaderLabels(headerList);
    //table->verticalHeader()->setVisible(false);
    table->horizontalHeader()->setStretchLastSection(true);


    table->setItem(0,0,new QTableWidgetItem("0"));
    table->setItem(1,0,new QTableWidgetItem("1"));
    table->setItem(2,0,new QTableWidgetItem("2"));


    table->setItem(0,1,new QTableWidgetItem("小王"));
    table->setItem(1,1,new QTableWidgetItem("小龙"));
    table->setItem(2,1,new QTableWidgetItem("小李"));
    gridLayout->addWidget(table,1,3,4,2);

    layout->addLayout(gridLayout);
    setLayout(layout);

效果是这样的

最后附上全部代码和资源

转载请注明出处

  • 7
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值