Design Around The GUI?

May 14, 2020 at 8:11am
Bit of a premature question here as I'm only on lesson 5.5 but I have an application in mind with many logic gates already thought out.

I'm quite worried about the GUI. I'm just learning C++ & have invested a few weeks already. Don't really have time to learn another language & the close relationship to machine code is what draws me towards C++. Some say the GUI should be thought of & coded first. Then your application wrapped around the GUI.
What would be the advice of some experienced hands?

I'm planning on using CGAL for geometric calculation https://doc.cgal.org/latest/Manual/packages.html though not sure which exact package yet. At the very bottom of that link they support plugins through the IPE Extensible Drawing Editor, but I would much prefer a 3D rendering engine. But as this is my first project in C++ maybe I'll have to use the IPE first. Then a later version I could think about 3D rendering.
Also QT/ xlWidgets are GUI options, but I wonder how it'll be going through one GUI, then passing it to my code, then to CGAL. I'm hoping CGAL has some more recommendations for GUI's but I haven't even begun to scratch the surface yet. I'm just working my way through the tutorials & ensuring I understand each topic before moving forward.

Grateful of any early input.
May 14, 2020 at 8:53am
Some say the GUI should be thought of & coded first. Then your application wrapped around the GUI.

+1 to that!
But you should know 90% of programmers who wrote their own GUI would never try to do it again ;) (those 10% just like working on such projects)

Writing code is easy but, it takes a lot of work just to make a good design, and I'm telling you from my xp. but I don't regret it because there simply isn't GUI library that would impress me for random reasons which are my personal preference.

Also QT/ xlWidgets are GUI options

Go ahead and see for your self, many people will recommend you such libraries (but not me)
Since as you said you're learning it's perfectly valid to first learn from libraries that somebody else made, for simple reason which is that you'll know how stuff is made and designed.
So sometime in the future you will have a good starting point on how to do something.

I'm planning on using CGAL for geometric calculation

CGAL looks like some mathematical library? didn't read much from the link you gave, but I would not start with mathematics first, because you won't need math in the very start.

but I would much prefer a 3D rendering engine

I can't recommend you rendering engine libraries because it too much to eat.
Instead to better invest your time learning would be to learn how to draw primitives first, such as circles and cubes.

the close relationship to machine code is what draws me towards C++

+1 to that too!
You'll get many suggestions but my suggestion for a beginner is to use something that has very good documentation, IMO, because lack of documentation is the reason why I provide such suggestions in the first place.

Lack of documentation is No.1 reason why people don't use some library, and documentation doesn't mean just online resources but also code comments, forum posts, youtube videos etc. without this you'll get overwhelmed by complexity of code, trust me ;)

So what is my recommendation then?
1. Window API for writing your own GUI
2. DirectX for drawing
3. And for mathematics it's perfectly valid to re-use some good library because writing your own math is seriously hard thing to do, reason No.1 is that you'll never reach the performance of already tested algorhitms even if you sacrifice accuracy which is then yet another problem.

Why?
1. *Every* function is super documented and you'll learn fast
2. Internet is full of sample code and developers who will be able to help you
3. Since you like "relationship to machine code" this is exactly what you may want to try out, because it's the lowest level you can go with C++

EDIT:
Ah I forgot some links:
https://docs.microsoft.com/en-us/windows/win32/learnwin32/learn-to-program-for-windows
https://docs.microsoft.com/en-us/windows/win32/direct2d/getting-started-with-direct2d-nav
Last edited on May 14, 2020 at 9:03am
May 14, 2020 at 9:12am
Thanks malibor, fantastic input; very grateful, links are exactly what I'm after.

I wish I could jump in right now, but I better finish my tutorials first. I'm so tempted to jump into Direct2D now, but I must stay strong.

EDIT - Presumably Direct2D is far more simpler than Microsoft DriectX?
Last edited on May 14, 2020 at 9:16am
May 14, 2020 at 9:48am
Presumably Direct2D is far more simpler than Microsoft DriectX?

Actually Direct2D is subset of DirectX, (meaning Direct2D is DirectX)
Another components is Direct3D, and the difference is I guess self explanatory?

Yes it's pretty much simple to use, you can draw your scene pretty easy and how ever you like, just remember one thing:
1. Reuse your own code, what ever you write save it somewhere for copy/paste or write a reusable class,
because writing same code over and over again isn't of much learning benefit (since nobody can memorize all anyway) and just slows down learning progress toward new things.

I wish I could jump in right now, but I better finish my tutorials first.

Do what ever fits you appetite, best learning is when you enjoy it!
Last edited on May 14, 2020 at 9:50am
May 14, 2020 at 1:46pm
I prefer to code the hard worker stuff first, as if gui did not exist at all. Here, do not put in any printers, only getters. Main can make a cout << thing.getx() << thing.gety() if you need to print it. Same for input, in main cin>> tmp; thing.setx(tmp); Etc. Same for files and network and whatever. Keep all the I/O out of your main code.
Then putting a gui on it is just stringing the I/O of the gui to interface with your working code.

Where that breaks down are the parts of the code that are really part of the GUI: menus, graphics, sounds, text with fonts and fancy stuff, etc are all so heavily tied to the libraries you are using that doing the above will not work. If your program is mostly made up of things like this, where the work being done is directly coupled to the gui framework, the above will just make an unnecessary split in code that could have been a nice single block.

The trick is seeing which is which in the early design phases.

The biggest thing I am looking to do when coding is to be able to quickly and easily change gui technologies (eg microsoft to QT), where the only re-work is to do the new gui and call the rest of it as before and have it just work, or to be able to make a stripped down console version that does some or all of the work without the gui, as a utility (think winzip: you can open the gui or just zip from the command line). Whether these things are useful to you or not may also govern how you go about it. That, and I had a bad experience where we made a project and all the classes were visual studio gui aware. It would only work on visual studio, nothing could be saved to move it off, and editing non gui related things still required knowing the framework, etc. It was nearly as bad as that managed code mess they do now.
May 14, 2020 at 2:06pm
Thanks jonnin, that's helpful to have another perspective.

The trouble is I have no knowledge of how a GUI works. I've read & watched a few tutorials, so understand it'll be a main loop continuously checking if any events have changed & then going from there. I'm looking forward to learning it. The thing that scares me is time, as there's so much to absorb. Grateful of the lockdown at the moment & trying to make the most of it.

Thanks again for your input.
May 14, 2020 at 5:14pm
most of the 'looping' you talk about is hidden from you in the libraries. For a simple gui program (no graphics or hand-drawing stuff) all you really need to be aware of is what happens when the user interacts with one of your widgets like pushing a button, selecting from a menu, or typing in an text area, etc. You have to keep in mind that the user can activate these things at any time in any order, so you can't blow up the program if the user hits the menu before typing a value or types a value before hitting a button; every piece needs to work (or gracefully tell the user what not to do / what to do) stand-alone.

**looping may, and probably does, mean threading these days. I don't really know what goes on deep inside, but it could fire off threads each listening for its event, or it could loop over all events, to see if any of them hit. Both work, but modern pcs are very thread friendly with each chip having 4+ cpus and each cpu capable of handling at least 2 if not closer to 10 decently complex threads before it starts to struggle. The number of small simple threads running on an unclean (standard installs, not tweaked to kill useless processes) windows box is astonishing.

Last edited on May 14, 2020 at 5:16pm
May 14, 2020 at 8:40pm
Thanks jonnin, that makes sense.

Malibor I started having a look at Direct 2D today as I felt I was making good progress with my tutorials.
But I failed miserably with your link to drawing a rectangle, it's only early days mind you but I would've thought I should've got that done in under 2 hours. Virtual Studio complained about each and every library. Just a couple of questions relating to Direct 2D. I'm trying to find decent tutorials on it which clearly show what's needed. I'm going to install some more stuff into Visual Studio for Microsoft 2D. Doing some more reading on it atm.

1 - Will it be possible to import a pdf into it? Thanks for your recommendation of Microsoft Direct 2D, that will work well with what I need for now I think (providing I can import pdfs into it).

2 - There are quite a few different links to Microsoft 2D. The most prominent links seem to be the link you kindly provided. But the tutorial doesn't specify exactly what headers need to be included; it refers to normal windows headers, which is a little ambiguous on such essential info. I might follow these tutorials https://youtu.be/p91FvlnyOyo but I'd much rather follow a written guide.

3 - I can't find much on Microsoft 2D since 2018, it seems to be only on 32-bit architecture. Ideally I'm looking to deploy on 64-bit architecture. I don't have time to learn a different system really, is Microsoft 2D definitely what I should be using? I imagine it is or you wouldn't have recommended it, but just checking.


EDIT - I got the header files working properly now I think as this info was several docs away. Still getting lots of errors but I'll keep pressing on with them. I'm reading through all the documentation to see if there's other basic tutorials to get a grasp on it.
Last edited on May 14, 2020 at 9:22pm
May 14, 2020 at 9:23pm
Will it be possible to import a pdf into it?

I'm not sure what you mean by this, how do you plan to use pdf file format in VS or DirectX?

But the tutorial doesn't specify exactly what headers need to be included

The headers and libraries you need are: (put these into your source file)
1
2
3
#include <windows.h> // Windows API (Win32)
#include <d2d1.h>  // Direct2D API
#pragma comment(lib, "d2d1") // link to Direct2D library 


it seems to be only on 32-bit architecture

Not true, it's platform independent, you may be confused about "Win32" word? it just means Windows API, the name it self doesn't mean 32 bit windows only.

but I'd much rather follow a written guide.

You'll need to get used to MSDN documentation if you want to learn, I personally don't follow youtube and random tutorials on web unless really stuck, because MSDN docs are just good enough, but that's just me, you may need to know C++ better first and then later learn windows to better understand the docs.

Btw. docs do mention what you need to include and link, it's just you didn't read hard enough, probably because you just wanted to copy/paste code and compile sample program. it doesn't work that way.
It mentions these thing on the link I gave you here:
https://docs.microsoft.com/en-us/windows/win32/direct2d/the-direct2d-api#direct2d-header-files

Here is fully compilable example I dug from my archived code, make a new project in VS, and create those 2 files, switch to Debug x64 configuration and run the program:

basewin.h

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
#pragma once
#include <Windows.h>

template <class DERIVED_TYPE>
class BaseWindow
{
public:
	static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		DERIVED_TYPE *pThis = NULL;

		if (uMsg == WM_NCCREATE)
		{
			CREATESTRUCT* pCreate = (CREATESTRUCT*)lParam;
			pThis = (DERIVED_TYPE*)pCreate->lpCreateParams;
			SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);

			pThis->m_hwnd = hwnd;
		}
		else
		{
			pThis = (DERIVED_TYPE*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
		}
		if (pThis)
		{
			return pThis->HandleMessage(uMsg, wParam, lParam);
		}
		else
		{
			return DefWindowProc(hwnd, uMsg, wParam, lParam);
		}
	}

	BaseWindow() : m_hwnd(NULL) { }

	BOOL Create(
		PCWSTR lpWindowName,
		DWORD dwStyle,
		DWORD dwExStyle = 0,
		int x = CW_USEDEFAULT,
		int y = CW_USEDEFAULT,
		int nWidth = CW_USEDEFAULT,
		int nHeight = CW_USEDEFAULT,
		HWND hWndParent = 0,
		HMENU hMenu = 0
	)
	{
		WNDCLASS wc = { 0 };

		wc.lpfnWndProc = DERIVED_TYPE::WindowProc;
		wc.hInstance = GetModuleHandle(NULL);
		wc.lpszClassName = ClassName();

		RegisterClass(&wc);

		m_hwnd = CreateWindowEx(
			dwExStyle, ClassName(), lpWindowName, dwStyle, x, y,
			nWidth, nHeight, hWndParent, hMenu, GetModuleHandle(NULL), this
		);

		return (m_hwnd ? TRUE : FALSE);
	}

	HWND Window() const { return m_hwnd; }

protected:

	virtual PCWSTR  ClassName() const = 0;
	virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) = 0;

	HWND m_hwnd;
};


source.cpp

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
#include <windows.h>
#include <d2d1.h>
#pragma comment(lib, "d2d1")

#include "basewin.h"

template <class T> void SafeRelease(T **ppT)
{
	if (*ppT)
	{
		(*ppT)->Release();
		*ppT = NULL;
	}
}

class MainWindow : public BaseWindow<MainWindow>
{
	ID2D1Factory            *pFactory;
	ID2D1HwndRenderTarget   *pRenderTarget;
	ID2D1SolidColorBrush    *pBrush;
	D2D1_ELLIPSE            ellipse;

	void    CalculateLayout();
	HRESULT CreateGraphicsResources();
	void    DiscardGraphicsResources();
	void    OnPaint();
	void    Resize();

public:

	MainWindow() : pFactory(NULL), pRenderTarget(NULL), pBrush(NULL)
	{
	}

	PCWSTR  ClassName() const { return L"Circle Window Class"; }
	LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
};

// Recalculate drawing layout when the size of the window changes.

void MainWindow::CalculateLayout()
{
	if (pRenderTarget != NULL)
	{
		D2D1_SIZE_F size = pRenderTarget->GetSize();
		const float x = size.width / 2;
		const float y = size.height / 2;
		const float radius = min(x, y);
		ellipse = D2D1::Ellipse(D2D1::Point2F(x, y), radius, radius);
	}
}

HRESULT MainWindow::CreateGraphicsResources()
{
	HRESULT hr = S_OK;
	if (pRenderTarget == NULL)
	{
		RECT rc;
		GetClientRect(m_hwnd, &rc);

		D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);

		hr = pFactory->CreateHwndRenderTarget(
			D2D1::RenderTargetProperties(),
			D2D1::HwndRenderTargetProperties(m_hwnd, size),
			&pRenderTarget);

		if (SUCCEEDED(hr))
		{
			const D2D1_COLOR_F color = D2D1::ColorF(1.0f, 1.0f, 0);
			hr = pRenderTarget->CreateSolidColorBrush(color, &pBrush);

			if (SUCCEEDED(hr))
			{
				CalculateLayout();
			}
		}
	}
	return hr;
}

void MainWindow::DiscardGraphicsResources()
{
	SafeRelease(&pRenderTarget);
	SafeRelease(&pBrush);
}

void MainWindow::OnPaint()
{
	HRESULT hr = CreateGraphicsResources();
	if (SUCCEEDED(hr))
	{
		PAINTSTRUCT ps;
		BeginPaint(m_hwnd, &ps);

		pRenderTarget->BeginDraw();

		pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::SkyBlue));
		pRenderTarget->FillEllipse(ellipse, pBrush);

		hr = pRenderTarget->EndDraw();
		if (FAILED(hr) || hr == D2DERR_RECREATE_TARGET)
		{
			DiscardGraphicsResources();
		}
		EndPaint(m_hwnd, &ps);
	}
}

void MainWindow::Resize()
{
	if (pRenderTarget != NULL)
	{
		RECT rc;
		GetClientRect(m_hwnd, &rc);

		D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);

		pRenderTarget->Resize(size);
		CalculateLayout();
		InvalidateRect(m_hwnd, NULL, FALSE);
	}
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR, int nCmdShow)
{
	MainWindow win;

	if (!win.Create(L"Circle", WS_OVERLAPPEDWINDOW))
	{
		return 0;
	}

	ShowWindow(win.Window(), nCmdShow);

	// Run the message loop.

	MSG msg = { };
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return 0;
}

LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_CREATE:
		if (FAILED(D2D1CreateFactory(
			D2D1_FACTORY_TYPE_SINGLE_THREADED, &pFactory)))
		{
			return -1;  // Fail CreateWindowEx.
		}
		return 0;

	case WM_DESTROY:
		DiscardGraphicsResources();
		SafeRelease(&pFactory);
		PostQuitMessage(0);
		return 0;

	case WM_PAINT:
		OnPaint();
		return 0;
	case WM_SIZE:
		Resize();
		return 0;
	}
	return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
}
Last edited on May 14, 2020 at 9:32pm
May 14, 2020 at 9:51pm
Thanks malibor, I found the headers in the end, but they listed half a dozen or so & you've only included a few at the top so I'm clearly not understanding it properly.

When I say import pdf I mean can I load a pdf into the background? The purpose is I want to draw ontop of a pdf (finished product).

I think it's clear I need to finish my tutorials on C++ first, then get into the API.

For the record I only copied and pasted after a few hours to see if the tutorial was correct.

I've been typing up every lesson by hand so far several times and altering and playing to see what happens when I change things. Like you say, copy and paste; absolutely no chance of learning anything.

Thanks again for your help, massively appreciated for you to go digging through your archive.

Right a quick play with your code as a little treat then back to standard C++ tutorials with the hope of generating a gui one day.
May 14, 2020 at 10:12pm
I mean can I load a pdf into the background?


I'm not sure how to do it, but there are 2 possible ways coming to my mind:
1. take a screenshot of pdf page you want, and loading and rendering the image should be easy then.
2. otherwise you may need some 3rd party library capable of rendering a pdf file, although I don't think such library exists, but who knows, people write all sorts of libraries..

I whish you all the best on your journey with C++ ;)
Last edited on May 14, 2020 at 10:13pm
May 15, 2020 at 7:28pm
PDFs are hard to work with. its a mix of 1985 era postscript and a bunch of new stuff. Some pdfs have textual data you can search, some are just images of text. Some have fancy stuff like forms you can fill in parts of, others are really basic. The only way I know to work with them is to get a library to do so, and that will let you get to the file data such as it is but displaying it may be more tricky. I highly recommend you table working with PDF until you have the other areas of your program working and well understood, to avoid trying to learn to many things all at once.

Or, if your program's key feature is the PDF work, do that first and circle back to the rest.
I do not know if there is a plug in for visual studio or something that can just handle pdfs for you; these exist for microsoft's tools but pdf is adobe and if such a thing exists, it may cost money etc.

The only pdf program I wrote was to search a large library of them off name, date, and keywords type searching, and it worked but I ended up beating some free source code I found online into submission with a club, it wasn't pretty but it worked. I didn't display them myself but the user could pick a result and it would open it in adobe for them via a system() call.
Last edited on May 15, 2020 at 7:30pm
Topic archived. No new replies allowed.