OpenGL and Windows
Windows Forms
Programming
Roger Crawfis
Creating a nice GUI
• The next several slides will walk you thru a
particular design that I like for my
applications.
• The order can be a little finicky, so if you
mess up, delete all files and start over!!!
• The design consists of a GUI panel on the
left and a view panel on the right, with a
status bar and a main menu.
Note: VS 2003 shown
• The following slides and images are old,
create a new project using 2005.
• Also, note there is a new SplitContainer
that works better for this style of GUI.
– Use it rather than the Panel/Splitter/Panel
approach.
Create a new Project
• Start Visual Studio .NET
Create a new Project
• Select a C++ Windows Forms Application
Add your GUI elements
• Resize the Form to be about 800 by 600,
or whatever you like.
• In this order, add the following elements
from the Toolbox->Windows Forms.
– StatusBar
– Panel
– Splitter
– Panel
GUI design
• In the Properties window you can make changes
to the content and appearance of these controls.
– Change the BackColor of the splitter.
– Change the Dock property of panel1 to Left.
– Change the Dock property of panel2 to Fill (the center
icon).
– Click on the Collections property of the statusBar and
add three tabs. Type in some text.
– On the StatusBar properties, set ShowPanels to true.
GUI Design
• Build (Build->Build Solution) and run
(Debug->Start without Debugging) your
application. It should look something like this:
GUI Design
• In the GUI panel, let’s make one large tabbed
dialogue.
• Drag a tabControl over to the GUI panel.
• Set its dock to Fill.
• In the properties select the Collection button and
add four tab panels.
–
–
–
–
Lab2
Extra
Grading
Readme
GUI Design
• Your program should now look like this.
New Title added
Background
image added
Examine the code
• Okay. We have the basic lay-out. Notice we
have not done any programming yet.
• Right-click the Form1.h file in the Solution panel
and select Edit Code. We have:
– A public constructor
– A protected Dispose
– A private InitializeComponents
• What is this! The source code is in the .h file?
• Look at the Form1.cpp file.
InitializeComponents
• There is a tree view structure in the code views
with Visual Studio. You can collapse a method,
class or region of code to hide the details as you
work on other parts of the code.
• The InitializeComponents method is collapsed
by default. This is automatically generated by
the Designer Window. It has all of the natty
details on setting up the controls.
• Uncollapse it and examine the code.
Lab2
• Okay, we have the basic lay-out, now we
need to embed the business logic.
• What are the lab requirements?
• More specifically, what controls do we
need?
– Specifying the number of lines / points.
– Reading in (selecting) an image file.
– Specifying the line-width or point size.
– Specify two color values.
Lab2 Controls
•
Selecting an image file.
– Possible Options:
1. Add a text box and have the user type the path /
filename into the textbox. (umm Yuck!!!)
2. Pre-load a set of image files and have the user
select from this set. (lacks flexibility).
3. Bring up a dialog asking the user to select an
image. Limit the selection to only the proper type
of files.
•
•
How do we bring up the dialog?
What do we have to do to show the dialog?
Image file Dialogue
•
•
This is why you use a higher-level API.
With windows forms and .Net 1.1 this is
really trivial. Follow these simple steps:
1. Drag an OpenFileDialog control to anywhere
on your Form. Notice that it places it in a
special window pane below your design.
2. Drag a Button control to the Lab2 tab panel.
This will be used to bring up the dialog.
Image file Dialogue
•
Adjust the Button’s properties:
1.
•
Change the text to “Load Texture”
Adjust the OpenFileDialog’s properties
1.
2.
3.
4.
5.
Change the Title to “Select an image file for the texture”
In the Filter property add a string to aid in the right file type
selection. Something like this:
“All files (*.*)|*.*|Jpeg (*.jpg)|*.jpg|Png (*.png)|*.png”.
Each pair here has the format (Text string to display | regular
expression). Note that adding a space before the asterisk
results in a different regular expression.
Set the Filter index to 2, such that jpeg is the default format.
Set the AddExtension to False.
Make sure the Multiselect property is False.
Image file Dialogue
• Okay, we have now defined everything, such
that the constructor is called and the properties
are set. Nothing will happen though, we need to
add some logic.
• Double click the “Load Texture” button. This
adds some template code and brings up the
source code window (Form1.h).
• It also added this line inside the
InitializeComponents:
this->button1->Click += new System::EventHandler(this, button1_Click);
• Add the following line in button1_Click:
this->openFileDialog1->ShowDialog();
Image file Dialogue
• Run and test the program. Clicking on the
button should bring up the openFileDialog.
Image file Dialogue
• Note that the dialog simply selects the file,
it does not open it or perform any logic yet.
• We will address actually opening the file,
reading in the image and creating a
texture map from it later.
Lab2 Controls
• Number of primitives
– There are several choices here.
• Textbox (you would need to validate that it only
contained numbers).
• Numeric Up/Down control (it has two speeds, both
of which you can configure in the Properties page).
• Trackbar or slider control (you may need to provide
a text label that indicates the current value).
– The reference lab uses both a
numericUpDown and a Trackbar tightly
coupled together.
Accessibility
• Most controls have accessibility features
built into them.
• This allows for a mouse free control.
• You can hit the tab key to reach the
NumericUpDown and Trackbar controls
and then use the arrow keys to change
their values.
• Holding down the key accelerates the
change.
Trackbar
• Let’s use the trackbar.
• Drag a trackBar control to the Lab2 tab panel.
• In the Properties page:
–
–
–
–
–
Set the Maximum value to 100,000 (or higher)
Set the (initial or current) Value to 10,000
Set the LargeChange to 5,000
Set the SmallChange to 1,000
Set the Tick Frequency to 10,000
• Also add a Label control (static text) above the
trackBar to describe its purpose.
Trackbar
• We should now have something like:
Trackbar
•
Okay, we have a control and it can change values, etc.
but we do not have anything useful connected to it.
Business logic:
•
–
There are many ways you can use this:
1.
2.
3.
The lazy way – simply read the control’s value whenever you
need it. This mixes the business logic and the GUI logic.
The global document way – Whenever the value changes,
change a corresponding data value in some document class. This
still mixes the logic. Bad data hiding.
The document/view way – Whenever the value changes, call a
method on the document’s class. The document now knows it’s
value has changed.
•
•
Perform some action (update display, verify data, etc.)
Keep a history for undo/redo.
Document Class
• Okay, I will admit it, I used method #1 in the
reference lab. But I am going to make you follow
method #3.
• Create and add a new class to your project.
– Right-click on the solution and select
Add->Add Class from the context menu.
– Select a generic C++ class and give a name.
– Change it to managed C++ by changing class to
public __gc class in the header file.
– Add the following private members:
– int numPrimitives;
– float lineWidth;
– Color color1, color2;
Document Class
• You also need to include:
using namespace System::Drawing;
• Add public methods to set (and optionally
get) each of these. For instance:
void SetNumPrimitives( const int nLines ) { numPrimitives = nLines; }
•
Document Class
• Okay, now we can wire that to the trackBar.
• Double-click the trackBar in the designer.
• In the code template, add something like:
impressionismDoc->SetNumPrimitives( trackBar1->Value );
• We need to create and add an instance of our
document. Declare a private pointer to an
instance.
private: Impressionism *impressionismDoc;
• In the constructor for Form1 create a new
instance.
impressionismDoc = new Impressionism();
Lab2 Status
• Okay, we are about 1/3 of the way to
having some implementation for lab2.
• You need to add an OpenGLPanel as in
HW #1 and Lab1 and create the OpenGL
drawing calls.
• We also still need to add the image file
and texture map, as well as the other
controls.
Done
• The End
• Ignore the following slides!!
OhioState::OpenGLPanel
• The simplest possible canvas or rendering
context.
• No assumptions are made (single buffer,
double buffer, etc.)
• Burden on user to provide all information
and event processing.
• Can be used as a base-class for more
intelligent classes.
OpenGLPanel : Forms::Control
• All of the functionality of a Control.
• Creates the OpenGL rendering context.
• Overrides:
– protected OnPaintBackground
– protected OnPaint
– protected OnResize
– public set_BackColor property
Public methods
• OpenGLPanel( PIXELFORMATDESCRIPTOR pfd );
• void AddPreRenderCallback( OpenGLRenderCallback
*callback );
• void AddRenderCallback( OpenGLRenderCallback
*callback );
• void AddPostRenderCallback( OpenGLRenderCallback
*callback );
• void AddResizeCallback( OpenGLResizeCallback
*callback );
• int GetFrameNumber() { return frameNumber; };
• void MakeCurrent();
• void SwapBuffers();
The Constructor
• No assumptions, so the user passes in the
PIXELFORMATDESCRIPTOR which
indicates the number of color bits, stencil
bits, etc.
• Make sure the dwflag entry includes
PFD_SUPPORT_OPENGL.
• See the sample and the MSDN help for
more information.
Callbacks
• The OpenGLPanel is structured around
registered callbacks. These are pointers to a
function, or delegates.
• Two publicly defined Delegate types:
– public __delegate void OpenGLRenderCallback(
const int frameNumber );
– public __delegate void OpenGLResizeCallback( const
int width, const int height );
• These are really type definitions:
– A pointer to a function that returns void and takes one parameter
of type const int.
Callbacks
• Like any other type, you create and
instance:
thank-you
garbage collection
glPanel->AddRenderCallback( new
OhioState::OpenGLRenderCallback( this, DrawScene ) );
• DrawScene is a public method of this, or
Form1 here.
• Can also use static methods, in which
case, this would be replaced with the class
type.
Using OpenGLPanel
• Checklist:
– Create a Forms::Panel (in the designer).
– In the Form1 constructor:
• Create an OpenGLPanel and add it to the panel
(call this glPanel).
• Put all of your drawing code into a method that
returns void and takes a single const int.
• Create a callback instance and add it to glPanel.
• Create a resize function, wrap it in a callback and
add it to glPanel.
© Copyright 2026 Paperzz