update 2018.2.26:
新版本: https://pan.baidu.com/s/1hteaPbY (vs2017 only)
主要修改如下:
0)采用动态库,提供相关 .dll, .lib ( 仅含 export 的函数名等,供链接用)和.res 文件。
1)简化了EGE_ControlPanel和EGE_Ctl_ScrollBars类实例初始化接口,不再需要调用getHWnd(),传递绘图窗口句柄等.
2)EGE_ControlPanel支持任意透明度(0-100%)。
3)拦截了绘图窗口系统菜单( 不需修改 main() 程序),用于支持有限的菜单功能,如隐藏/显示UI 接口等。
4)增加了绘图窗口截图功能,文件名可自定义,支持 bmp,jpg,tif,gif,png 等5种格式。
5)增加了绘图窗口动态视屏保存功能,格式暂时没有选择,设定为 mpg4, 文件名用当前系统的日期和
时间标定。以.avi 为后缀。
6)还有一些bugs.绘图窗口程序偶尔会崩溃,可能是线程同步和消息处理的一些问题引起的。
======== 下面是旧版本 =========
经常被萌新们问到, 如何在EGE里面增加按钮以及弹出框之类的, 但是EGE并没有自带这些功能, 如果要实现这些功能, 还得自己去学习Windows API什么的。
所以有爱的 Samuel Ni 同学编写了一个小巧易用的ui库, 可以很容易地配合EGE使用, 让我们的小程序不仅仅只有简单的绘图窗口(如上图)
支持内嵌按钮, 滚动条等, 也支持非模态对话框。
下载链接1: https://pan.baidu.com/s/1i67emdJ (内置了vs2015的工程, 仅限vs2015使用)
下载链接2: https://pan.baidu.com/s/1bq3mK5T (内置了vs2017的工程, 仅限vs2017使用)
如果你正对使用EGE时无法增加按钮等烦恼不已, 那么看看这个也许会有意外收获~
下面为demo的源代码, Samuel Ni 同学写了详细的注释, 有什么疑问可以给他发邮件咨询(戳这里):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
/*** EGE 用户界面控件使用实例说明 所需文件一: EGE_UI_sLib.lib, 可以放在(和你的.cpp 主文件相同的)当前目录或任何你的编译链接程序的路径目录里 所需文件二: EGE_UI_sLib.res, 可以放在(和你的.cpp 主文件相同的)当前目录或任何你的链接程序的 link 路径目录里 所需文件三: EGE_UI_sLib.h, 可以放在(和你的.cpp 主文件相同的)当前目录或任何你的编译程序的Include 路径目录里 使用方法举例: 假定你使用 MSVC (各个版本的)编译链接程序, 而你的 EGE graphics.h 和 graphics.lib 的位置/路径设置 已经无误( 参见EGE库的使用文档 ),你可以用以下的命令行编译链接你的.cpp 和 EGE_UI 用户界面库: cl.exe /I your_include_path\ Your.cpp /link /LIBPATH:your_lib_path\ EGE_UI_sLib.lib EGE_UI_sLib.res 假如你在你的 your.cpp 开头加了#pragma comment(lib,"EGE_UI_sLib.lib"),而EGE_UI_sLib.lib 在当前目录,命令行可以稍微简单一点: cl.exe /I your_include_path\ Your.cpp /link /LIBPATH:your_lib_path\ EGE_UI_sLib.res (cl.exe 各参数的用法,参见MS 的文档,或输入 cl.exe /? ) 注1: EGE_UI_sLib.lib 是试验性的,目前只支持一个功能有限 Modeless 对话框,其上加载了三个ScrollBar控件 和三个按钮控件, 你必须在你的main() 里对按钮返回的消息作出适当处理,否则程序可能会崩溃。 EGE_UI_sLib.lib 还提供最多10 个 定制性更灵活的 ScrollBar控件,可以用于在运行时改变你的.cpp 中的全局变量 或 main(){}定义的局部变量数值, 变量类型支持 double, float 和 int, 使用方法参见本实例。 注2: 相关控件名字字符串还不支持 Unicode 宽字符,但也许能正确显示中文字符,视你的电脑 Local 环境而定 注3: 更多使用方法请见本实例的其他注释部分 注4: EGE_UI_sLib.lib 还在实验中,有潜在的Bugs, 原代码书写还不规范,等 celanup 并提供更多功能后将提供原代码。 欢迎提出意见和建议。 作者: Samuel Ni, 2018 年 2 月,上海 联系: samuel_ni@yahoo.com or samuelni@mail.sim.ac.cn (提供以上联系方式但作者可能无法保证(及时)回复发到上述邮箱的所有邮件。) ***/ #include "EGE_UI_sLib.h" #include <graphics.h> #include <time.h> #include <math.h> #include <new.h> #pragma comment(lib,"EGE_UI_sLib.lib") UINT _MyGetCh() { key_msg KeyMsg = getkey(); KeyMsg.key = KeyMsg.key | KeyMsg.flags; return KeyMsg.key; } int main() { int wd, ht; int n = 150; int key; // 绘图循环中用于捕获键盘输入并加以处理...... double G = 1.5; // general gravity constant 这个变量在本实例中将通过控件做运行时改变 double h = 0.001; // time step 这个变量在本实例中将通过控件做运行时改变 double dmin = 25.0; // min allowed distance between objects 这个变量在本实例中将通过控件做运行时改变 int mx, my, k, j; double ang, v, dx, dy, d, a, ax, ay; double Sx, Sy, Svx, Svy, Sm; wd = 900; // 主程序绘图窗口宽度 ht = 700; // 主程序绘图窗口高度 mx = wd - 1; my = ht - 1; setinitmode(0); // noShow EGE logo initgraph(wd, ht); ////////////////////////////////////////////////////////////////////////////// // 在绘图或动画例程之前声明一个 ControPanel,实质上是一个包含 // Windows本地风格控件的 modeless dialog 对话框 /////////////////////////////////////////////////////////////////////////////// ///////////////////////// set up the UI controls //////////////////////////////////// char szTestName[]="Test"; // 不要超过10个 ascii 字符 DLGPARAMS dp; // 声明Modaless 对话框所需的数据,数据类型在 EGE_UI_sLib.h 定义 dp.P1Min = - 100.0; // 类型可以是 double, float 和 int dp.P1Max = +100.0; dp.P1 = G; // 变量G 和对话框上一个ScrollBar控件挂钩,变量的 Scope 可以是 Global 或main() {} dp.szP1Name = "g.."; // 随便起一个名字,长度限制在10个 Ascii 字符内,库函数还没有做chat 类型数组的bound 检查... // 超长的名字可能会引起程序崩溃 dp.fScaleP1 = 1.0; // 把dp.P1Min 和 dp.P1Max 变换到 【P1Min*fScaleP1,P1Min*fScaleP1】的整数范围 // 库函数目前还没有自动选取合适的 Scale 的功能... stay tune.... dp.P2Min = 0.0001 ; // 以下是对话框上第二个 ScrollBar 对应的数据.... dp.P2Max = 0.01; dp.P2 = h; dp.szP2Name = "h.."; // 测试常量字串 dp.fScaleP2 = 10000.0; dp.P3Min = 1.0; // 以下是对话框上第三个 ScrollBar 对应的数据.... dp.P3Max = 50.0; dp.P3 = dmin; dp.szP3Name = szTestName;// 测试变量字串 dp.fScaleP3 = 1.0; // 对话框实例化 ...通常一个实例足矣...多于一个实例系统也许会崩溃,还未测试 // 这里的中文字符串是尝试性的,不一定能正确显示 EGE_ControlPanel MyControPanel(TEXT("程序主控面板"), dp,getHWnd(),getHInstance()); //EGE_ControlPanel(ControlPanelCaption, dpUser,getHWnd(),getHInstance()); // 以下 三个 Scroll Bar 控件直接以右对齐的方法放在主程序窗口用户绘图区 SCROLLPARAMS dpScrollBar; // 声明第一个Scroll Bar 控件相关的数据结构类型,数据类型在 EGE_UI_sLib.h 定义 SCROLLPARAMS dpGBar; // 声明第二个Scroll Bar 控件 ... SCROLLPARAMS dpStarNumer; // 声明第三个Scroll Bar 控件 ...最多可以声明10 个超出无效 // 如果你的绘图区高度不够,最后实例化的控件可能看不见 dpGBar.PMin = - 100.0; // 通过函数重载, 类型可以是 double, float 和 int ,但类型不能混用,见EGE_UI_sLib.h... dpGBar.PMax = +100.0; dpGBar.P = G; dpGBar.fScaleP = 1.0; dpScrollBar.PMin = 0.0001 ; dpScrollBar.PMax = 0.01; dpScrollBar.P = h; dpScrollBar.fScaleP = 10000.0; dpStarNumer.PMin = 2 ; dpStarNumer.PMax = 600; dpStarNumer.P = n; dpStarNumer.fScaleP = 1; // 实例化三个ScrollBar 控件。初始化函数(constructor)第一个参数用于显示控件名称以及对应的变量显示格式 // 显示格式(format)串的定义,沿用 标准 C printf("format string", Var) 的规定,可以参见有关printf() 的文档 // 例如:%-6.3f 表示 左对齐显示一个6位数的浮点数,保留3位小数 // ScrollBar 控件还有bug, 你最好都用浮点数格式显示所有的数据, double, float, int, whatever // 这个实例中,物理单位的显示没有实际意义,实例中的物理模型算法也是不符实际的 // 试一试, 假如G 变成负的, what's happening ? EGE_Ctl_ScrollBars GScrollBar("Gravity constant G=%-6.3f(N*M2*Kg-2) ", dpGBar,getHWnd(),getHInstance()); EGE_Ctl_ScrollBars StarNumerScrollBar("Number of Stars N=%3.0f ", dpStarNumer,getHWnd(),getHInstance()); EGE_Ctl_ScrollBars MyScrollBar("Iteration Length h=%e(s)", dpScrollBar,getHWnd(),getHInstance()); /////////////// That's all you have to do to set up the UI controls ...//////////////////// Label_Reset : // 如果你使用控件中的 ReSet 按钮,要确保跳转到合适的初始化位置, // 否则你的main() 可能会崩溃。 // 如果你的 ScrollBar 控件和某些与内存动态分配有关的变量挂钩 // 比例这里的 n, 也必需做合适的处理并跳到合适的位置,否则系统 // 几乎一定会崩溃 .....Bule Screen at lower version of Windows double* m = new double[n]; double* x = new double[n]; double* y = new double[n]; double* vx = new double[n]; double* vy = new double[n]; color_t* clr = new color_t[n]; cleardevice(); Sx = Sy = Svx = Svy = Sm = 0; randomize(); //以下代码和绘图与物理模拟运算有关,和 GEG UI 控件用法没有直接关系 for (k = 0; k < n; ++k) { x[k] = (((double) randomf() * 2.0 - 1.0) * (double) mx / 8.0 + (double) mx / 2.0); y[k] = (((double) randomf() * 2.0 - 1.0) * (double) my / 8.0 + (double) my / 2.0); m[k] = ((double) randomf() * 30.0) + 10.0; m[k] = (m[k] * m[k] * m[k]) * 10.0; ang = ((double) randomf() * 2.0 * PI); v = ((double) randomf() * 60.0); vx[k] = (v * (double) cos(ang)); vy[k] = (v * (double) sin(ang)); clr[k] = hsl2rgb(randomf() * 360, randomf(), randomf()); } for (k = 0; k < n; k++) { Sx = Sx + m[k] * x[k]; Sy = Sy + m[k] * y[k]; Svx = Svx + m[k] * vx[k]; Svy = Svy + m[k] * vy[k]; Sm = Sm + m[k]; x[k] = x[k] - (Sx / Sm) + (mx / 2.0); y[k] = y[k] - (Sy / Sm) + (my / 2.0); vx[k] = vx[k] - (Svx / Sm); vy[k] = vy[k] - (Svy / Sm); } do{ for (k = 0; k < n; k++) { ax = 0; ay = 0; for (j = 0; j < n; ++j) { if (k != j) { dx = x[j] - x[k]; dy = y[j] - y[k]; d = (double) sqrt(dx * dx + dy * dy); d = (double) max(dmin, d); dx = dx / d; dy = dy / d; a = G * m[j] / (d * d); ax = ax + a * dx; ay = ay + a * dy; } } vx[k] = vx[k] + ax * h; vy[k] = vy[k] + ay * h; x[k] = x[k] + vx[k] * h; y[k] = y[k] + vy[k] * h; putpixel((int) x[k], (int) y[k], clr[k]); } // 以上代码和绘图与物理模拟运算有关,和 GEG UI 控件用法没有直接关系 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //处理发给 ControPanel的消息 并 检测ControPanel上控件对参数的修改 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////* if (StarNumerScrollBar.getUserParameter(&n)) { delete[] m; // 这里 n 的改变 可能引起 Mememory leak 进而程序崩溃 delete[] x ; // 所以你必须在问题发生之前做相应处理, delete[] y ; delete[] vx ; delete[] vy ; delete[] clr ; goto Label_Reset; // "goto" 久违了,千年来一回 } MyScrollBar.getUserParameter(&h); // 这里 h 和 G 的改变,不会导致程序崩溃,所以你不需做特别处理 GScrollBar.getUserParameter(&G); // 当然,你也可以在 h 和 G的改变发生影响时,做以下其他预处理。 // 你一定要对 对话框MyControPanel实例返回的信息做适当处理, 这是设计这个 UI 库 本身的目, // 如果你不处理这些消息,你不需要实例化这个 UI EGE_CPReturnCode ret = MyControPanel.getUserParameter(&G, &h, &dmin); switch (ret) { case EGE_CP_NO_EVENT: // Nothing happens ...... you can delete this Case ..... break; case EGE_CP_NEW_DATA: // some parameter being updated, you are given chance to do something here { break; } case EGE_CP_RESET: // 你按了 "ReSet " 按钮.... { delete[] m; delete[] x ; delete[] y ; delete[] vx ; delete[] vy ; delete[] clr ; goto Label_Reset; } case EGE_CP_EXIT: // 你按了 "Exit " 按钮,准备退出 main().......yor will hear a Beep! goto Label_Exit; } if (kbhit())key = _MyGetCh(); } while (key != key_esc); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// Label_Exit : delete[] m; delete[] x ; delete[] y ; delete[] vx ; delete[] vy ; delete[] clr ; closegraph(); return 0; } |
近期评论