前言
準備開新坑了。這個坑可大可小,而且我不急於一個月兩個月寫完這第一篇。目前在學QT,所以打算用QT做。先做個視覺小說來設計一個簡單的框架,然後在年底開始第二階段,打算做個小遊戲編輯工具——按去年那時我的想法來說,這個工具可以算是引擎了——雖然我以前下載了GameMaker和RPGMaker但是不怎麼會用,但是最近幾乎每天都在B站上看一個UP直播恐怖遊戲,而且似乎都是RPGMaker做的。看的多了,又讓我想起了曾經的激情。
視圖、場景、圖形項
首先需要被介紹的概念是視口和窗口。這兩個概念都是用來表示window,並不一定指同一個,兩個概念中的window的座標系不同。
視口以左上角爲原點,窗口以中心爲原點。
視圖就是一個視口,場景和圖形項都是窗口。視圖是場景的父項,場景項是圖形項的父項,而圖形項下還可以有圖形項。圖形項包括矩形、橢圓、多邊形、直線、文字、圖片等。
My_GraphicsView
新建一個繼承於QMainWindow的項目,在編輯UI時刪除工具欄和狀態欄,菜單欄可能之後有用。設置MainWindow的初始大小爲805X505,這是爲了保證裏面的窗口大小是800X500。還需要設置最小大小爲805X505。
在MainWindow中先放入一個Scroll Area,然後右鍵佈局爲柵格佈局。然後在其中放入一個Graphics View控件,右鍵佈局爲柵格佈局。把兩個佈局的屬性,比如佈局寬度等設置爲零。
對QGraphicsView類進行提升,更改爲一個自定義的子類,比如My_GraphicsView(之後會定義)
然後新建C++ Class,命名爲My_GraphicsView,繼承於QGraphicsView
//my_graphicsview.h
#pragma once
#include <QGraphicsView>
class My_GraphicsView : public QGraphicsView
{
Q_OBJECT
public:
My_GraphicsView(QWidget* parent=nullptr);
}
//my_graphicsview.cpp
#include "my_graphicsview.h"
My_GraphicsView::My_GraphicsView(QWidget* parent):QGraphicsView (parent)
{
}
自定義消息與自定義槽
1、QT兩大系統,信號與槽,屬性系統。屬性系統沒怎麼用過,但是信號與槽很熟悉了。在編輯UI時,在Signals and Slots Editor可以定義一整套信號發送和接收流程,當然是簡單的。比如定義當Pushbutton按下時,發送信號到窗口,觸發窗口的關閉。這種自動的、非代碼的信號與槽操作只能做一些簡單的效果。
2、想要個性的話需要在某個控件或者Action上右擊,選擇轉到槽,然後從跳出的窗口中多個slot函數中選擇一個,這樣就可以在選擇的slots函數內進行代碼操作。這是第二個階段。
第二個階段的信號與槽的使用還存在些限制,一是自動創建的slot函數是固定的,只能從有限的幾個裏面選擇,二是隻能操作在ui界面的控件或者是Action上,對於不出現在ui界面上的動作沒有辦法。
3、然後更高級一點就是自定義slot和自定義關聯。自動創建的slot是不用自己去手動關聯的,其信號發送者和接收者是一一對應的。除此之外的其他關聯就需要自己做,自己定義的槽函數也需要自己關聯。
簡而言之,自動創建的slot只能一對一,而複雜的情況還有很多——多對一、一對多、多對多。
4、之後就是自定義signals、自定義slots、自定義關聯。所謂的信號,不過是個命名而已,不需要實現,信號函數的名字只用作區分其與其他信號。
//my_graphicsview.h
protected:
void keyPressEvent(QKeyEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
signals:
void s_keyClicked(QKeyEvent* event);
void s_mouseDoubleClicked(QPoint point);//這個用不到
void s_mouseClicked(QPoint point);
void s_mouseMove(QPoint point);
//my_graphicsview.cpp
void My_GraphicsView::keyPressEvent(QKeyEvent *event){
// static int i=0;
// qDebug()<<"keyPressEvent被執行了 "<<++i;
emit s_keyClicked(event);
QGraphicsView::keyPressEvent(event);
}
void My_GraphicsView::mouseDoubleClickEvent(QMouseEvent *event){
// static int i=0;
// qDebug()<<"mouseDoubleClickEvent "<<++i;
if(event->button()==Qt::LeftButton){
QPoint p=event->pos();
emit s_mouseDoubleClicked(p);
}
QGraphicsView::mouseDoubleClickEvent(event);
}
void My_GraphicsView::mousePressEvent(QMouseEvent *event){
// static int i=0;
// qDebug()<<"mousePressEvent "<<++i;
if(event->button()==Qt::LeftButton){
QPoint p=event->pos();
emit s_mouseClicked(p);
}
QGraphicsView::mousePressEvent(event);
}
void My_GraphicsView::mouseMoveEvent(QMouseEvent *event){
// static int i=0;
// qDebug()<<"mouseMoveEvent "<<++i;
QPoint p=event->pos();
emit s_mouseMove(p);
QGraphicsView::mouseMoveEvent(event);
}
接收My_GraphicsView信號及相關處理
在加載文件時爲什麼使用…/untitled/images/*** 而不使用 images/*** 是因爲build與項目文件目錄不同,而本地路徑是從其可執行文件開始的,所以需要跳出 build 文件夾,再到項目文件夾下去選擇資源。
這個GALGAME Demo實現了貼圖、按鈕、文本框、文字、按鍵處理、按F11全屏、按C切圖
//mainwindow.h
#pragma once
#include <QMainWindow>
#include <QFileDialog>
#include <QDebug>
#include <QMainWindow>
#include <QGraphicsScene>
#include <QLabel>
#include <QGraphicsItem>
#include <QTime>
#include <QDialog>
#include <QColorDialog>
#include <QFontDialog>
#include <QFileDialog>
#include <QInputDialog>//輸入對話框
#include <QGraphicsRotation>
#include <QGraphicsDropShadowEffect>
#include <QMessageBox>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots: //自定義slots
void on_keyClicked(QKeyEvent* event);
void on_mouseClicked(QPoint point);
void on_mouseMove(QPoint point);
//重寫接口
protected:
void resizeEvent(QResizeEvent* event);
void paintEvent(QPaintEvent *event);
void closeEvent(QCloseEvent* event);
private:
QGraphicsScene* scene;
int flag_interface=1;
void paint1(QPaintEvent* event);
void paint2(QPaintEvent* event);
private:
Ui::MainWindow *ui;
};
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowTitle("untitled");//窗口名
//mouse1.png中心被當做鼠標原點,所以箭頭被放在了右下角的位置,保證箭頭
//頂點就是鼠標原點
setCursor(QCursor(QPixmap("../untitled/images/mouse1.png")));//自定義光標
//爲視圖設置一個場景
int w=width()-5;//右下角座標(895,595)
int h=height()-5;
scene=new QGraphicsScene(-w/2,-h/2,w,h);
ui->view->setScene(scene);
//ui->view->setCursor(Qt::CrossCursor);
ui->view->setMouseTracking(true);
ui->view->setBackgroundBrush(QBrush(Qt::white));
ui->view->setDragMode(QGraphicsView::NoDrag);
connect(ui->view,SIGNAL(s_keyClicked(QKeyEvent*)),this,SLOT(on_keyClicked(QKeyEvent*)));
connect(ui->view,SIGNAL(s_mouseClicked(QPoint)),this,SLOT(on_mouseClicked(QPoint)));
connect(ui->view,SIGNAL(s_mouseMove(QPoint)),this,SLOT(on_mouseMove(QPoint)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_keyClicked(QKeyEvent* event){
if(event->key()==Qt::Key_Escape){
showNormal();
}
else if(event->key()==Qt::Key_F11){
if(isFullScreen())showNormal();
else showFullScreen();
}
else if(event->key()==Qt::Key_C){
flag_interface=!flag_interface;
qDebug()<<"flag_interface="<<flag_interface;
repaint();//強行觸發paintEvent
//update();//在Qt下一次處理事件時才調用一次繪製事件
}
}
void MainWindow::on_mouseClicked(QPoint point){
QGraphicsItem* it=ui->view->itemAt(point);
if(it!=nullptr){
static int i=0;
qDebug()<<"yes "<<++i;
}
}
void MainWindow::on_mouseMove(QPoint point){
qDebug()<<"mouse at>>"<<point.x()<<","<<point.y();
}
void MainWindow::resizeEvent(QResizeEvent* event){
static int i=0;
qDebug()<<"resizeEvent被執行了 "<<++i;
//如何同比例放大呢?除了全屏外都是同樣的比例,全屏可以不同
//to be continue
}
void MainWindow::paintEvent(QPaintEvent *event){
static int i=0;
qDebug()<<"paint... "<<++i;
if(flag_interface==1)paint1(event);
else
paint2(event);
QMainWindow::paintEvent(event);
}
void MainWindow::closeEvent(QCloseEvent* event){
QMessageBox::StandardButton result=QMessageBox::question(this,
"╭(╯^╰)╮","確定退出遊戲嗎?",
QMessageBox::Yes|QMessageBox::Cancel,
QMessageBox::Cancel);
if(result==QMessageBox::Yes)event->accept();
else event->ignore();
}
void MainWindow::paint1(QPaintEvent* event){
int w=width()-5;
int h=height()-5;
//背景
QGraphicsPixmapItem* it2=new QGraphicsPixmapItem;
QPixmap pix2;
pix2.load("../untitled/images/background.jpg");//加載一張圖片
QPixmap p=pix2.scaled(w+2,h+2);
it2->setPixmap(p);
it2->setPos(-w/2,-h/2);
scene->addItem(it2);
//按鈕
QGraphicsRectItem* it=new QGraphicsRectItem(0,0,100,40);
QPixmap texturePixmap("../untitled/images/texture.png");
QBrush brush;
brush.setStyle(Qt::TexturePattern);
brush.setTexture(texturePixmap);
it->setBrush(brush);
it->setPen(Qt::NoPen);//無邊框
it->setPos(0,0);
scene->addItem(it);
//貼一張文本框的圖
QGraphicsPixmapItem* it4=new QGraphicsPixmapItem;
QPixmap pix;
pix.load("../untitled/images/text_frame.png");//加載一張圖片
QPixmap p2=pix.scaledToWidth(w+2);
it4->setPixmap(p2);
it4->setPos(-w/2,-h/2);
scene->addItem(it4);
//文字
//做一個圖形項:文字
QGraphicsTextItem* it3=new QGraphicsTextItem("小鵬[優紀就由由乃來保護(*^▽^*)]");
QFont font=this->font();//返回是一個地址
font.setBold(true);
font.setPointSize(20);
it3->setFont(font);
it3->setDefaultTextColor(QColor(100,100,100));
it3->setPos(-w/2,h/2-100);
scene->addItem(it3);
}
void MainWindow::paint2(QPaintEvent* event){
int w=width()-5;
int h=height()-5;
//背景
QGraphicsPixmapItem* it2=new QGraphicsPixmapItem;
QPixmap pix2;
pix2.load("../untitled/images/good.jpg");//加載一張圖片
QPixmap p=pix2.scaled(w+2,h+2);
it2->setPixmap(p);
it2->setPos(-w/2,-h/2);
scene->addItem(it2);
}
執行效果在最後
其他
解決中文亂碼
在pro文件裏添加下面的內容
win32-msvc*: {
QMAKE_CFLAGS *= /utf-8
QMAKE_CXXFLAGS *= /utf-8
}
添加資源
在項目目錄裏建一個文件夾images,在其中存放一些要用到的圖片。
1、在項目裏新建一個qrc類型的資源文件file.qrc
2、在file.qrc上右擊選擇Open in Editor
3、添加一個前綴,把默認前綴 /new/prefix1 改爲images
3、添加文件,把文件加images裏的圖片都添加上
設置程序圖標
找張ICO類型的圖片,或者使用格式工廠來轉換一張圖片爲ICO類型。把這種圖片添加到資源裏後,在pro文件裏添加下面這一行,即找到這張圖片的位置
RC_ICONS = images/app.ico
設置鼠標光標
在MainWindow類中,可以爲這個窗口類設置光標,也可以爲視圖 ui->view 設置光標。這些光標都可以看做圖形項,當設置一張圖片爲光標時,圖片中心就是光標的頂點——所以在畫光標的時候,需要把箭頭畫在圖片四分之一的右下角的區域,這樣箭頭的頂點就是光標的原點了。
setCursor(Qt::CrossCursor);//十字光標
setCursor(Qt::WaitCursor);//圓圈光標
//...
setCursor(QCursor(QPixmap("images/mouse1.png")));//自定義光標
發佈程序
1,首先選擇一個Release,編譯一下
2,一般項目目錄與build目錄是不同的,在Release對應的build目錄中找到可執行文件 untitled.exe 。這時候點擊但是執行不了,但是沒事不用管。
3,把 untitled.exe 放入一個新建的文件夾中,比如E:\DOP
4,找到一個QT部署工具,在開始裏面找。必須選擇對應Release的版本的。
4,點擊打開這個工具後,找到 untitled.exe ,使用 windeployqt untitled.exe
來部署。
這時候程序就自動把要用到的DLL都添加過來了——這裏有個images文件夾需要自己複製過來。可是就算這樣,點擊可執行文件後沒有圖片!!
因爲build與項目目錄是分開的,資源文件放在項目文件夾裏,而可執行文件在另外的地方。所以這時候可以修改程序裏的文件相對路徑就行了。修改後再找到新的untitled.exe,複製過來替換這一個,一切OK。
5、刪除點沒用的,刪除完後這個目錄還有18.7MB
執行效果如下
參考:
《Qt5.9 C++開發指南》
QT之程序發佈以及打包成exe安裝包
Qt打包程序提示“應用程序無法正常啓動(0xc000007b)”解決方案