0


【C++图形化界面】使用HiEasyX优化黑框输入输出交互界面

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>usingnamespace std;

hiex::Canvas canvas_main;
hiex::SysEdit edit;
hiex::SysButton btn;
hiex::SysCheckBox checkbox;
hiex::SysStatic text;#defineWND_W640#defineWND_H480#defineEDIT_W480#defineEDIT_H400#defineBTN_X20#defineBTN_Y430#defineCHECKBOX_X140#defineCHECKBOX_Y435#defineSTATIC_X260#defineSTATIC_Y440#defineWINDOW_LONG1000// 显示窗口的长#defineWINDOW_WIDE600// 显示窗口的宽#defineEDIT_LONG800// 编辑窗口的长#defineEDIT_WIDE480// 编辑窗口的宽voidOutInfo(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
    );}// 连续输出垂直文字// 调用前需要自行设置文字垂直属性voidVerticalText(LPCTSTR lpsz,bool text_c, COLORREF cText,bool  bk_c, COLORREF cBk,bool set =false,int x =0,int y =0){staticint 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;}return0;}voidOptionsWnd(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;}voidOnClick(){staticbool running =false;if(!running){
        running =true;
        std::thread(OptionsWnd,&running).detach();}}voidOnCheck(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());returnstring(buf.data(), buf.size());}intfile_xcopy_stod(constchar* source_dir,constchar* 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;}//开始读写constint FLUSH_NUM =1024*1024;//缓冲区大小设置为1Mchar* 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();return0;}// 输出 1 词法分析 的窗口voiddraw_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 语法分析 递归下降 过程 的窗口voiddraw_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 的窗口voiddraw_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 过程 的窗口voiddraw_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 的窗口voiddraw_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 语义分析 的窗口voiddraw_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);}voidinit(){

    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 =newchar[pSize +1];//第二次调用将双字节字符串转换成单字节字符串WideCharToMultiByte(CP_OEMCP,0, pWCStrKey,wcslen(pWCStrKey), pCStrKey, pSize,NULL,NULL);
    pCStrKey[pSize]='\0';return pCStrKey;//如果想要转换成string,直接赋值即可//string pKey = pCStrKey;}// 绘制菜单界面voiddrawMenu(){
    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();}intmain(){init();// 清空文件drawMenu();// SNL菜单界面return0;}

4.注意事项

(1)使用x86或x64问题

编译此界面的vs设置,与需要调用的程序编译时的设置必须相同。
在这里插入图片描述
当时就因为这个问题我没注意,一个x64,一个x86,结果明明我把界面输入的内容写入了文件,但被调用的程序一直显示无法打开文件并且无法识别。

暴改好久,真的哭死。

前车之鉴,后车之师!铭记如此惨痛的教训!

(2)输出文件的路径

由于界面显示时需要读新产生的文件,它的位置在你的具体项目程序中设定的位置。由于我在项目程序中用的相对路径,所以新生成的文件位置在界面文件夹里。

当时我在项目文件夹中没发现输出文件更新,还以为没调用运行成功,换了很多调用函数,之后不小心打开界面文件夹才发现。可以说是非常愚蠢了,这里也耽误了巨久,就是没第一个问题那么久hhhhh。

(3)其他问题

其余都是可以多查查、速览定义等等就能解决的问题。

5.总结

综上所示,可以看出对编程水平不高的小白,实现简单的图形化界面其实并没有想象中的难,熟练掌握后半天就能做出来。只是由于此处基础知识的匮乏,所以实际处理过程中会遇到很多简单但很非常耽误进展的问题。

希望这篇记录,让自己不要忘记此过程中遇到的种种问题与困难,同时希望帮助到像我一样零基础的人。

标签: c++ 交互 c#

本文转载自: https://blog.csdn.net/qq_51351004/article/details/130261826
版权归原作者 今晚吃奥利奥炒酸奶 所有, 如有侵权,请联系我们删除。

“【C++图形化界面】使用HiEasyX优化黑框输入输出交互界面”的评论:

还没有评论