问题
I'm designing a simple GUI framework from scratch as a project, using OpenGL and nothing else external and need some advice on how I might implement user interaction.
Basically, I've a base class GUIItem
from which all elements inherit. This gives each item some basic variables such as position, a vector to contain child elements as well as some basic functions for mouse movement and clicking.
All elements are setup as above, with their relevant member variables.
What I'm struggling with is how to implement user interaction properly. In my window manager I would create a new instance of an item, say GUIButton
and call it button1
. The window manager would, upon a click occurring, iterate through its list of elements and any child elements they may have, calculating a rectangular area around the object based on its coordinates, height and width, then running any "on click" function associated with said item, like change the value of textlabel1
.
Firstly, is there a better way to do this calculation? It would work for rectangular elements but spherical objects and others would have a much larger erroneous area which could be clicked. Ideally I would check pixels but I've no real idea how that would be achieved. I've heard about but never used GLUT (my project only allows use of this for handling mouse/keyboard interaction though). Does GLUT provide anything to assist in this case?
My main issue is with handling what would occur when an "On click" event actually occurred. At the moment GUIButton
for example, has an "On click" function built in, so as far as I can see, I'd have to do something like make it a virtual function, meaning that each new button I created would have to have its own class just to overwrite the "on click" function and each instance of a button would be an instance of a unique class that simply inherited off of GUIButton
. This seems messy to me, as I've no idea where I would store all those classes, and it seems a lot of extra code. Would I be creating a button1.cpp and button1.h file?
Any advice on this really would be welcome as I'm new to C++, OpenGL and it's the first time I've been exposed to GUI programming and there's not a lot to go on when an existing GUI framework is the usual choice.
回答1:
if you want something stupidly simple and fast then you could:
- create shadow screen buffer containing
ID/index/pointer
instead of color pre-render this buffer
Just render each of your visual component to it but instead coloring/texturing just fill in the
ID/index/pointer
of rendered component. Do not forget to clear this with someNULL
first ... After this you should have mask of your components. You need to do this just once ...On mouse events
you simply convert mouse coordinates to the shadow screen space and pick the value. If it is
NULL
then you clicked or whatever on empty area. If it containsID
instead update or call the callbacks for componentID
. if you have a list of all components then ID can be the list index, otherwise use its actual pointer or encode in style(component_type, component_index)
. As you can see this is pretty fastO(1)
item selection no matter how many components you have ... The shadow screen can have different resolution then your actual screen (to preserve memory).
This have pixel perfect mouse selection accuracy no matter the shape of your components without the need for nested component search loops.
[Notes]
As I did this stuff here are some hints:
create a window
class containing configuration of your components for single screen. Programs have usually more screens with different set of components and doing dynamically the screens over and over again just because you switch page/screen sucks.
use separate list of components one list per component type.
create IDE editor for your windows see drag & drop example in C++ it might get handy for this. Add get,set
functions controlled by string/enum or flag
to easy obtain/change properties to make Object Inspector possible. Also this is how mine IDE looks like:
The window is saved from IDE directly as C++ code I can just copy to my App. This is the above example without the knob (forgot to save it):
//---------------------------------------------------------------------------
// OpenGL VCL window beg: win
win.grid.allocate(0);
win.grid.num=0;
win.scale.allocate(0);
win.scale.num=0;
win.button.allocate(0);
win.button.num=0;
win.knob.allocate(0);
win.knob.num=0;
win.scrollbar.allocate(3);
win.scrollbar.num=3;
win.scrollbar[0].x0=200.0;
win.scrollbar[0].y0=19.0;
win.scrollbar[0].xs=256.0;
win.scrollbar[0].ys=16.0;
win.scrollbar[0].fxs=8.0;
win.scrollbar[0].fys=19.0;
win.scrollbar[0].name="_vcl_scrollbar0";
win.scrollbar[0].hint="";
win.scrollbar[0].min=0.000;
win.scrollbar[0].max=1.000;
win.scrollbar[0].pos=0.000;
win.scrollbar[0].dpos=0.100;
win.scrollbar[0].horizontal=1;
win.scrollbar[0].style=0;
win.scrollbar[0].resize();
win.scrollbar[1].x0=200.0;
win.scrollbar[1].y0=45.0;
win.scrollbar[1].xs=256.0;
win.scrollbar[1].ys=16.0;
win.scrollbar[1].fxs=8.0;
win.scrollbar[1].fys=19.0;
win.scrollbar[1].name="_vcl_scrollbar1";
win.scrollbar[1].hint="";
win.scrollbar[1].min=0.000;
win.scrollbar[1].max=1.000;
win.scrollbar[1].pos=0.000;
win.scrollbar[1].dpos=0.100;
win.scrollbar[1].horizontal=1;
win.scrollbar[1].style=0;
win.scrollbar[1].resize();
win.scrollbar[2].x0=200.0;
win.scrollbar[2].y0=70.0;
win.scrollbar[2].xs=256.0;
win.scrollbar[2].ys=16.0;
win.scrollbar[2].fxs=8.0;
win.scrollbar[2].fys=19.0;
win.scrollbar[2].name="_vcl_scrollbar2";
win.scrollbar[2].hint="";
win.scrollbar[2].min=0.000;
win.scrollbar[2].max=1.000;
win.scrollbar[2].pos=0.000;
win.scrollbar[2].dpos=0.100;
win.scrollbar[2].horizontal=1;
win.scrollbar[2].style=0;
win.scrollbar[2].resize();
win.interpbox.allocate(0);
win.interpbox.num=0;
win.dblist.allocate(0);
win.dblist.num=0;
// OpenGL VCL window end: win
//---------------------------------------------------------------------------
Look at images here plotting real time Data on Oscillocope for some ideas (I got this working for both GDI and OpenGL)
It is better to use pixel units instead of OpenGL <-1,+1>
screen units for better visual quality and editing comfort.
来源:https://stackoverflow.com/questions/34247742/simple-opengl-gui-framework-user-interaction-advice