1.简介
实现一份不错的课程设计,往往需要利于进行实现良好交互的图形化界面。
在这学期的课程设计中,我发现了一套可以通用的图形化界面,适合需要界面,但不需要多高级的界面的,并且像我一样图形化知识基础为0的C/C++小白。
现记录如下:
(1)运行环境:VS2019
(2)实现效果:
①在编辑框内可以输入内容(能实现改变字号、字体、字色、背景颜色,设置只读等基础设置),将输入的内容写入到文件中
②调用其他程序的exe(想优化输入输出的那个程序)
③可点击按钮,查看运行结果
(3)待继续优化的方向:
①目前输入、输出无法支持中文,只能全英。
②打开初始界面后,若点开了其他如浏览器等覆盖该界面后,编辑框有一定几率会直接不见。
2.完成过程
(1)发现需要实现简单的图形化界面问题,主要满足大学课设的一般需求。
(2)考虑过QT和C#,没使用的原因很简单,就是对这两个完全没什么了解,并且希望只凭借自己浅薄的C/C++的知识就能实现,不需要多么高级的效果。
(3)了解发现easyx该文件可以实现简单的图形化界面,于是着手开始实践。但是等到实现了后,发现当前的效果只能是:
输入我要输入的文本后,点击按钮后可以换个新界面并能弹出一些文本信息。因为其可以插入背景图片,这个的背景图就是我用PPT完成的。其余界面类似如此格式的PPT风。
由于我对easyx也没了解,不希望系统学习其相关的函数等,只希望学当前需要用到的部分,所以直接找的完整项目,从中直接找的需要部分。
我学习的项目是GitHub上的c-easyx-TypingGame-main,这是个小萝卜打字游戏,实现得非常完善有趣。从中能直接学到如何使用easyx实现输出界面、设置背景图片、实现按钮点击变色的效果、如何实现鼠标交互、返回菜单、背景音乐等等可以应用的知识。
完成后,发现其最大的弊端是,我需要的输出的内容行数很多,使用简单的弹窗或者直接输出在界面上根本无法放下,也没有右边的下拉条等。
但如果你的项目输出输入简单,不需要输出一个界面放不下的内容,这个会是这个不错的选择。
虽然界面蛮不错,但这里无奈弃用。
(4)在搜索解决以上问题的过程中,发现了GitHub上扩展的HiEasyX库,能够实现有下拉框的编辑框(可进行长文本输入输出)、多窗口等。因此果断换成使用这个实现。
传送门:HiEasyX库
(5)实现具体效果如下图所示,满足我的长文本输入输出基本需求。
3.具体实现
以上图片的源码如下,就是在那篇GitHub上的示例项目上多改一改就能实现。
简言之,画界面,while判断鼠标点击按钮,并弹出新的编辑框输出相应内容,可以多个窗口同时存在进行对比分析等。
以下代码并不是全有用,因当时时间有限,能达到目标效果后就没再优化了,若参考的话可自行删减一些无用代码。
#include "HiEasyX.h"
#include <fstream>
#include <bits/stdc++.h>
#include <conio.h>
#include <stdlib.h>
#include <Windows.h>
using namespace std;
hiex::Canvas canvas_main;
hiex::SysEdit edit;
hiex::SysButton btn;
hiex::SysCheckBox checkbox;
hiex::SysStatic text;
#define WND_W 640
#define WND_H 480
#define EDIT_W 480
#define EDIT_H 400
#define BTN_X 20
#define BTN_Y 430
#define CHECKBOX_X 140
#define CHECKBOX_Y 435
#define STATIC_X 260
#define STATIC_Y 440
#define WINDOW_LONG 1000 // 显示窗口的长
#define WINDOW_WIDE 600 // 显示窗口的宽
#define EDIT_LONG 800 // 编辑窗口的长
#define EDIT_WIDE 480 // 编辑窗口的宽
void OutInfo(hiex::Canvas& canvas)
{
static LPCTSTR lpszText = L"Created by HiEasyX " _HIEASYX_VER_STR_;
canvas.SetTextEscapement(0);
canvas.SetTextOrientation(0);
canvas.SetTextStyle(16, 0, L"Arial");
canvas.OutTextXY(
canvas.GetWidth() - canvas.TextWidth(lpszText),
canvas.GetHeight() - canvas.TextHeight(lpszText),
lpszText,
true, GRAY
);
}
// 连续输出垂直文字
// 调用前需要自行设置文字垂直属性
void VerticalText(LPCTSTR lpsz, bool text_c, COLORREF cText, bool bk_c, COLORREF cBk, bool set = false, int x = 0, int y = 0)
{
static int sx = 0, sy = 0;
if (set)
{
sx = x;
sy = y;
}
if (text_c)
settextcolor(cText);
if (bk_c)
setbkcolor(cBk);
outtextxy(sx, sy, lpsz);
sy += textwidth(lpsz);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static COLORREF bk = CLASSICGRAY;
switch (msg)
{
case WM_PAINT:
canvas_main.SetTextEscapement(-900);
canvas_main.SetTextOrientation(-900);
canvas_main.SetTextStyle(140, 0, L"微软雅黑");
canvas_main.BeginBatchDrawing();
VerticalText(L"Hi", true, LIGHTRED, true, SKYBLUE, true, getwidth() + 10, 20);
VerticalText(L" ", false, 0, true, bk);
VerticalText(L"E", true, WHITE, true, RED);
VerticalText(L"a", false, 0, true, ORANGE);
VerticalText(L"s", false, 0, true, GREEN);
VerticalText(L"y", false, 0, true, CYAN);
VerticalText(L"X", false, 0, true, BLUE);
canvas_main.EndBatchDrawing();
canvas_main.SetBkColor(bk);
OutInfo(canvas_main);
break;
case WM_SIZE:
{
canvas_main.Clear(true, bk);
int dx = canvas_main.GetWidth() - WND_W;
int dy = canvas_main.GetHeight() - WND_H;
edit.Resize(
EDIT_W + dx,
EDIT_H + dy
);
btn.Move(BTN_X, BTN_Y + dy);
checkbox.Move(CHECKBOX_X, CHECKBOX_Y + dy);
text.Move(STATIC_X, STATIC_Y + dy);
break;
}
default:
return HIWINDOW_DEFAULT_PROC;
break;
}
return 0;
}
void OptionsWnd(bool* running)
{
static std::map<std::wstring, COLORREF> color_map = {
{L"black", BLACK},
{L"white", WHITE},
{L"gray", GRAY},
{L"red", RED},
{L"purple", PURPLE},
{L"orange", ORANGE},
{L"yellow", YELLOW},
{L"green", GREEN},
{L"blue", BLUE},
{L"cyan", CYAN}
};
static std::wstring typeface[] = {
L"system", L"Arial", L"Consolas", L"微软雅黑", L"宋体", L"仿宋", L"黑体"
};
hiex::Window wnd_option(300, 300);
SetWindowText(wnd_option.GetHandle(), L"Option");
hiex::Canvas canvas;
wnd_option.BindCanvas(&canvas);
OutInfo(canvas);
canvas.SetTypeface(L"System");
DisableResizing(wnd_option.GetHandle(), true);
hiex::SysComboBox combobox_ctext;
hiex::SysComboBox combobox_cbk;
hiex::SysComboBox combobox_typeface;
hiex::SysRadioButton radio[2];
canvas.SetTextColor(GRAY);
canvas.OutTextXY(20, 20, L"Select text color");
combobox_ctext.PreSetStyle({ false, false, true });
combobox_ctext.Create(wnd_option.GetHandle(), 20, 40, 260, 200);
canvas.OutTextXY(20, 80, L"Select background color");
combobox_cbk.PreSetStyle({ false, false, true });
combobox_cbk.Create(wnd_option.GetHandle(), 20, 100, 260, 200);
canvas.OutTextXY(20, 140, L"Select typeface");
combobox_typeface.PreSetStyle({ false, true, true });
combobox_typeface.Create(wnd_option.GetHandle(), 20, 160, 260, 200);
for (auto& color : color_map)
{
combobox_ctext.AddString(color.first);
combobox_cbk.AddString(color.first);
}
for (auto& name : typeface)
{
combobox_typeface.AddString(name);
}
combobox_ctext.SetSel(0);
combobox_ctext.RegisterSelMessage([](int nSel, std::wstring wstrSelText) {
edit.SetTextColor(color_map[wstrSelText]);
});
combobox_cbk.SelectString(L"white"); // 通过字符串选择项
combobox_cbk.RegisterSelMessage([](int nSel, std::wstring wstrSelText) {
edit.SetTextBkColor(color_map[wstrSelText]);
edit.SetBkColor(color_map[wstrSelText]);
});
combobox_typeface.SelectString(L"微软雅黑");
combobox_typeface.RegisterSelMessage([](int nSel, std::wstring wstrSelText) {
edit.SetFont(26, 0, wstrSelText);
});
combobox_typeface.RegisterEditMessage([](std::wstring wstrText) {
edit.SetFont(26, 0, wstrText);
});
radio[0].Create(wnd_option.GetHandle(), 20, 200, 100, 30, L"Left align");
radio[1].Create(wnd_option.GetHandle(), 20, 230, 100, 30, L"Right align");
radio[0].Check(true);
radio[0].RegisterMessage([](bool checked) {
if (checked)
edit.RightAlign(false);
});
radio[1].RegisterMessage([](bool checked) {
if (checked)
edit.RightAlign(true);
});
wnd_option.Redraw();
hiex::init_end(wnd_option.GetHandle());
*running = false;
}
void OnClick()
{
static bool running = false;
if (!running)
{
running = true;
std::thread(OptionsWnd, &running).detach();
}
}
void OnCheck(bool checked)
{
edit.ReadOnly(checked);
}
string to_string(const wstring& str, const locale& loc = locale())
{
vector<char>buf(str.size());
use_facet<ctype<wchar_t>>(loc).narrow(str.data(), str.data() + str.size(), '*', buf.data());
return string(buf.data(), buf.size());
}
int file_xcopy_stod(const char* source_dir, const char* destination_dir)
{
ifstream infile(source_dir, ios::in | ios::binary);//二进制形式打开
if (infile.is_open() == 0) {//出错处理
cout << "文件" << source_dir << "打开失败" << endl;
return -1;
}
ofstream outfile(destination_dir, ios::out | ios::binary);//二进制形式打开
if (outfile.is_open() == 0) {//出错处理
cout << "文件" << destination_dir << "打开失败" << endl;
infile.close();//记得关闭
infile.clear();
return -1;
}
//开始读写
const int FLUSH_NUM = 1024 * 1024;//缓冲区大小设置为1M
char* ch = new(nothrow)char[FLUSH_NUM];
if (ch == NULL) {//出错处理
cout << "动态申请内存失败" << endl;
infile.close();//记得关闭
infile.clear();
outfile.close();//记得关闭
outfile.clear();
return -1;
}
while (!infile.eof()) {
infile.read(ch, FLUSH_NUM);
outfile.write(ch, infile.gcount());//写入读入的成功个数
}
delete[]ch;//记得释放
infile.close();//记得关闭
infile.clear();
outfile.close();//记得关闭
outfile.clear();
return 0;
}
// 输出 1 词法分析 的窗口
void draw_1() {
hiex::Window wnd1(WINDOW_LONG, WINDOW_WIDE);
wnd1.SetProcFunc(WndProc);
hiex::AutoExit();
hiex::SysEdit edit1;
HWND hwnd1 = wnd1.GetHandle();
ifstream in("lexical_out.txt", ios::in);
if (in.fail())
MessageBox(wnd1.GetHandle(), L"文件打开失败", L"Submit", MB_OK);
istreambuf_iterator<char>beg(in), end;
wstring strdata(beg, end);
edit1.PreSetStyle({ true, false, true });
edit1.Create(hwnd1, 100, 60, EDIT_LONG, EDIT_WIDE, strdata);
edit1.SetFont(20, 0, L"黑体");
in.close();
in.clear();
//hiex::init_end(hwnd1);
}
// 输出 2 语法分析 递归下降 过程 的窗口
void draw_2() {
hiex::Window wnd2(WINDOW_LONG, WINDOW_WIDE);
wnd2.SetProcFunc(WndProc);
hiex::AutoExit();
hiex::SysEdit edit2;
HWND hwnd2 = wnd2.GetHandle();
ifstream in("rec_out.txt", ios::in);
if (in.fail())
MessageBox(wnd2.GetHandle(), L"文件打开失败", L"Submit", MB_OK);
istreambuf_iterator<char>beg(in), end;
wstring strdata(beg, end);
edit2.PreSetStyle({ true, false, true });
edit2.Create(hwnd2, 100, 60, EDIT_LONG, EDIT_WIDE, strdata);
edit2.SetFont(20, 0, L"黑体");
in.close();
in.clear();
//hiex::init_end(hwnd2);
}
// 输出 3 语法分析 递归下降 tree 的窗口
void draw_3() {
hiex::Window wnd3(WINDOW_LONG, WINDOW_WIDE);
wnd3.SetProcFunc(WndProc);
hiex::AutoExit();
hiex::SysEdit edit3;
HWND hwnd3 = wnd3.GetHandle();
ifstream in("rec_des_out.txt", ios::in);
if (in.fail())
MessageBox(wnd3.GetHandle(), L"文件打开失败", L"Submit", MB_OK);
istreambuf_iterator<char>beg(in), end;
wstring strdata(beg, end);
edit3.PreSetStyle({ true, false, true });
edit3.Create(hwnd3, 100, 60, EDIT_LONG, EDIT_WIDE, strdata);
edit3.SetFont(20, 0, L"黑体");
in.close();
in.clear();
//hiex::init_end(hwnd3);
}
// 输出 4 语法分析 LL1 过程 的窗口
void draw_4() {
hiex::Window wnd4(WINDOW_LONG, WINDOW_WIDE);
wnd4.SetProcFunc(WndProc);
hiex::AutoExit();
hiex::SysEdit edit4;
HWND hwnd4 = wnd4.GetHandle();
ifstream in("LL_1_process.txt", ios::in);
if (in.fail())
MessageBox(wnd4.GetHandle(), L"文件打开失败", L"Submit", MB_OK);
istreambuf_iterator<char>beg(in), end;
wstring strdata(beg, end);
edit4.PreSetStyle({ true, false, true });
edit4.Create(hwnd4, 100, 60, EDIT_LONG, EDIT_WIDE, strdata);
edit4.SetFont(20, 0, L"微软雅黑");
in.close();
in.clear();
//hiex::init_end(hwnd4);
}
// 输出 5 语法分析 LL1 tree 的窗口
void draw_5() {
hiex::Window wnd5(WINDOW_LONG, WINDOW_WIDE);
wnd5.SetProcFunc(WndProc);
hiex::AutoExit();
hiex::SysEdit edit5;
HWND hwnd5 = wnd5.GetHandle();
ifstream in("LL_1_out.txt", ios::in);
if (in.fail())
MessageBox(wnd5.GetHandle(), L"文件打开失败", L"Submit", MB_OK);
istreambuf_iterator<char>beg(in), end;
wstring strdata(beg, end);
edit5.PreSetStyle({ true, false, true });
edit5.Create(hwnd5, 100, 60, EDIT_LONG, EDIT_WIDE, strdata);
edit5.SetFont(20, 0, L"黑体");
in.close();
in.clear();
//hiex::init_end(hwnd5);
}
// 输出 6 语义分析 的窗口
void draw_6() {
hiex::Window wnd6(WINDOW_LONG, WINDOW_WIDE);
wnd6.SetProcFunc(WndProc);
hiex::AutoExit();
hiex::SysEdit edit6;
HWND hwnd6 = wnd6.GetHandle();
ifstream in("yuyi.txt", ios::in);
if (in.fail())
MessageBox(wnd6.GetHandle(), L"文件打开失败", L"Submit", MB_OK);
istreambuf_iterator<char>beg(in), end;
wstring strdata(beg, end);
edit6.PreSetStyle({ true, false, true });
edit6.Create(hwnd6, 100, 60, EDIT_LONG, EDIT_WIDE, strdata);
edit6.SetFont(20, 0, L"黑体");
in.close();
in.clear();
//hiex::init_end(hwnd6);
}
void init() {
string file_name = "lexical_out.txt";
ofstream file_writer1(file_name, ios_base::out);
file_name = "rec_out.txt";
ofstream file_writer2(file_name, ios_base::out);
file_name = "rec_des_out.txt";
ofstream file_writer3(file_name, ios_base::out);
file_name = "LL_1_process.txt";
ofstream file_writer4(file_name, ios_base::out);
file_name = "LL_1_out.txt";
ofstream file_writer5(file_name, ios_base::out);
file_name = "yuyi.txt";
ofstream file_writer6(file_name, ios_base::out);
return;
}
char* wideCharToMultiByte(wchar_t* pWCStrKey)
{
//第一次调用确认转换后单字节字符串的长度,用于开辟空间
int pSize = WideCharToMultiByte(CP_OEMCP, 0, pWCStrKey, wcslen(pWCStrKey), NULL, 0, NULL, NULL);
char* pCStrKey = new char[pSize + 1];
//第二次调用将双字节字符串转换成单字节字符串
WideCharToMultiByte(CP_OEMCP, 0, pWCStrKey, wcslen(pWCStrKey), pCStrKey, pSize, NULL, NULL);
pCStrKey[pSize] = '\0';
return pCStrKey;
//如果想要转换成string,直接赋值即可
//string pKey = pCStrKey;
}
// 绘制菜单界面
void drawMenu()
{
hiex::Window wnd(WINDOW_LONG, WINDOW_WIDE);
wnd.SetProcFunc(WndProc);
// hiex::AutoExit();
HWND hwnd = wnd.GetHandle();
edit.PreSetStyle({ true, false, true });
edit.Create(hwnd, 30, 30, EDIT_LONG, EDIT_WIDE,
L"Welcome to SNL Compiler !\r\n"
L"\r\n"
L"Let's start it from the simple sample.\r\n"
);
edit.SetFont(26, 0, L"微软雅黑");
hiex::SysButton btn_o;
btn_o.Create(hwnd, 100, 520, 100, 50, L" Options...");
btn_o.RegisterMessage(OnClick);
checkbox.Create(hwnd, 230, 550, 100, 20, L"Read only");
checkbox.RegisterMessage(OnCheck);
// 提交 按钮
hiex::SysButton btn_s;
btn_s.Create(wnd.GetHandle(), 450, 520, 100, 50, L"Submit");
// 1.词法 按钮
hiex::SysButton btn_1;
btn_1.Create(wnd.GetHandle(), 860, 30, 90, 50, L"词法");
// 2.递归 按钮
hiex::SysButton btn_2;
btn_2.Create(wnd.GetHandle(), 860, 100, 90, 50, L"递归过程");
// 3.语法 - 递归 - 树 按钮
hiex::SysButton btn_3;
btn_3.Create(wnd.GetHandle(), 860, 170, 90, 50, L"递归tree");
// 4.语法 - ll 1 按钮
hiex::SysButton btn_4;
btn_4.Create(wnd.GetHandle(), 860, 240, 90, 50, L"LL1过程");
// 5.语法 - tree 按钮
hiex::SysButton btn_5;
btn_5.Create(wnd.GetHandle(), 860, 310, 90, 50, L"LL1tree");
// 6.语义 - 按钮
hiex::SysButton btn_6;
btn_6.Create(wnd.GetHandle(), 860, 380, 90, 50, L"语义");
/*
// 7.错误 - 按钮
hiex::SysButton btn_7;
btn_7.Create(wnd.GetHandle(), 860, 450, 90, 50, L"error");
*/
while (wnd.IsAlive()) {
// 按下 提交 按钮时,弹窗
if (btn_s.IsClicked()) {
MessageBox(wnd.GetHandle(), L"SNL源代码已提交", L"Submit", MB_OK);
// 将输入内容写到文件中
//ofstream outfile_snl;
ofstream outfile_snl("C:\\lexical_in.txt", ios::app); // 将输入内容写入的文件绝对路径
stringstream ss;
string temp = to_string(edit.GetText().c_str());
ss << temp;
outfile_snl << ss.str();
outfile_snl.close();
outfile_snl.clear();
ShellExecute(NULL, NULL, _T("C:\\Con.exe"), NULL, NULL, SW_NORMAL); // 调用的exe文件绝对路径
}
// 按下按钮 1 时,弹窗显示文本
if (btn_1.IsClicked()) {
draw_1();
}
// 按下按钮 2 时,弹窗显示文本
if (btn_2.IsClicked()) {
draw_2();
}
// 按下按钮 3 时,弹窗显示文本
if (btn_3.IsClicked()) {
draw_3();
}
// 按下按钮 4 时,弹窗显示文本
if (btn_4.IsClicked()) {
draw_4();
}
// 按下按钮 5 时,弹窗显示文本
if (btn_5.IsClicked()) {
draw_5();
}
// 按下按钮 6 时,弹窗显示文本
if (btn_6.IsClicked()) {
draw_6();
}
}
hiex::init_end(hwnd);
closegraph();
}
int main()
{
init(); // 清空文件
drawMenu(); // SNL菜单界面
return 0;
}
4.注意事项
(1)使用x86或x64问题
编译此界面的vs设置,与需要调用的程序编译时的设置必须相同。
当时就因为这个问题我没注意,一个x64,一个x86,结果明明我把界面输入的内容写入了文件,但被调用的程序一直显示无法打开文件并且无法识别。
暴改好久,真的哭死。
前车之鉴,后车之师!铭记如此惨痛的教训!
(2)输出文件的路径
由于界面显示时需要读新产生的文件,它的位置在你的具体项目程序中设定的位置。由于我在项目程序中用的相对路径,所以新生成的文件位置在界面文件夹里。
当时我在项目文件夹中没发现输出文件更新,还以为没调用运行成功,换了很多调用函数,之后不小心打开界面文件夹才发现。可以说是非常愚蠢了,这里也耽误了巨久,就是没第一个问题那么久hhhhh。
(3)其他问题
其余都是可以多查查、速览定义等等就能解决的问题。
5.总结
综上所示,可以看出对编程水平不高的小白,实现简单的图形化界面其实并没有想象中的难,熟练掌握后半天就能做出来。只是由于此处基础知识的匮乏,所以实际处理过程中会遇到很多简单但很非常耽误进展的问题。文章来源:https://www.toymoban.com/news/detail-501448.html
希望这篇记录,让自己不要忘记此过程中遇到的种种问题与困难,同时希望帮助到像我一样零基础的人。文章来源地址https://www.toymoban.com/news/detail-501448.html
到了这里,关于【C++图形化界面】使用HiEasyX优化黑框输入输出交互界面的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!