How to Center Output Console Window in C++ - c++

I am currently using the MoveWindow() function in the header Windows.h, and using this function, I can move and resize the output console window any way I want.
MoveWindow(GetConsoleWindow(), x, y, width, height, TRUE);
// x and y is the position of the topleft corner of window
However, I cannot figure out how to center the screen without hard-coding the position of the window. Is there a way to set the position of the window to change depending on the width and height that I set? Thanks!
P.S. I am pretty new to C++

Get the WindowRect ( not to confuse with the ClientWindow)of your screen and find middle position, but ClientRect will remain unchanged since we are not resizing.Try this snippet:
Edited: For proper centering and to allow user to specify the position
void MoveWindow(int posx, int posy)
{
RECT rectClient, rectWindow;
HWND hWnd = GetConsoleWindow();
GetClientRect(hWnd, &rectClient);
GetWindowRect(hWnd, &rectWindow);
MoveWindow(hWnd, posx, posy, rectClient.right - rectClient.left, rectClient.bottom - rectClient.top, TRUE);
}
void MoveCenter()
{
RECT rectClient, rectWindow;
HWND hWnd = GetConsoleWindow();
GetClientRect(hWnd, &rectClient);
GetWindowRect(hWnd, &rectWindow);
int posx, posy;
posx = GetSystemMetrics(SM_CXSCREEN) / 2 - (rectWindow.right - rectWindow.left) / 2,
posy = GetSystemMetrics(SM_CYSCREEN) / 2 - (rectWindow.bottom - rectWindow.top) / 2,
MoveWindow(hWnd, posx, posy, rectClient.right - rectClient.left, rectClient.bottom - rectClient.top, TRUE);
}
int main(int argc, char *argv[])
{
MoveWindow(10, 10);
return 0;
}

Related

D2D coordinates not matching screen coordinates

I am using D2D with D3D11. I have some code that uses GetCursorpos() from the windows API which is then converted to client coordinates and then draws a small circle at this position using D2D FillEllipse(). The screen to client coordinates work perfectly but for some reason D2D draws the circle a small distance from the expected location (tens of pixels) as if the coordinate had been scaled by a small factor so that the error gets larger as the circle is drawn further from (0, 0).
I noticed changing the dpi for the D2D1_RENDER_TARGET_PROPERTIES affects this 'scaling' so I suspect the problem has something to do with dpi. This is the code for creating the D2D render target from the DXGI surface I obtained from the swapchain in my D3D11 code.
// Create render target
float dpiX, dpiY;
this->factory->GetDesktopDpi(&dpiX, &dpiY);
D2D1_RENDER_TARGET_PROPERTIES rtDesc = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_HARDWARE,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
dpiX,
dpiY
);
AssertHResult(this->factory->CreateDxgiSurfaceRenderTarget(
surface.Get(),
&rtDesc,
&this->renderTarget
), "Failed to create D2D render target");
Here, dpiX and dpiY become 96 which I notice is also the constant that GetDpiForWindow() from the windows API returns when it is not dpi aware.
I want to know how I can fix my code so that it will draw the circle at the position given by GetCursorPos().
More relevant code:
Driver code
Vector3f cursPos = input.GetCursorPos();
DrawCircle(Colour::Green, cursPos.x, cursPos.y, 3/*radius*/);
Input
POINT pt{};
::GetCursorPos(&pt);
// Convert from screen pixels to client pixels
return ConvertPixelSpace(this->hWnd, (float)pt.x, (float)pt.x, PixelSpace::Screen, PixelSpace::Client);
Direct2D
void DrawCircle(const Colour& c, float centreX, float centreY, float radius, PixelSpace ps)
{
Vector3f centre = ConvertPixelSpace(this->gfx.hWnd, centreX, centreY, ps, PixelSpace::Client);
centreX = centre.x;
centreY = centre.y;
D2D1_ELLIPSE el{};
el.point.x = centreX;
el.point.y = centreY;
el.radiusX = radius;
el.radiusY = radius;
auto brush = this->CreateBrush(c);
this->renderTarget->FillEllipse(
&el,
brush.Get()
);
}
PixelSpace Conversion
Vector3f ConvertPixelSpace(HWND hWnd, float x, float y, PixelSpace curSpace, PixelSpace newSpace)
{
RECT rc = GetClientRectOfWindow(hWnd);
struct
{
float top, left, width, height;
} rectf;
rectf.top = static_cast<float>(rc.top);
rectf.left = static_cast<float>(rc.left);
rectf.width = static_cast<float>(rc.right - rc.left);
rectf.height = static_cast<float>(rc.bottom - rc.top);
// Convert to client space
if (curSpace == PixelSpace::Screen)
{
x -= rectf.left;
y -= rectf.top;
}
// Convert to new space
if (newSpace == PixelSpace::Screen)
{
x += rectf.left;
y += rectf.top;
}
return Vector3f(x, y);
}
RECT GetClientRectOfWindow(HWND hWnd)
{
RECT rc;
::GetClientRect(hWnd, &rc);
// Pretty sure these are valid casts.
// rc.top is stored directly after rc.left and this forms a POINT struct
ClientToScreen(hWnd, reinterpret_cast<POINT*>(&rc.left));
ClientToScreen(hWnd, reinterpret_cast<POINT*>(&rc.right));
return rc;
}
The problem was I was creating the D3D11 swapchain with the window area instead of the client area.
RECT rect{};
GetWindowRect(hWnd, &rect); // !!! This should be GetClientRect()
this->width = rect.right - rect.left;
this->height = rect.bottom - rect.top;
DXGI_SWAP_CHAIN_DESC scDesc{};
scDesc.BufferDesc.Width = width;
scDesc.BufferDesc.Height = height;
//...

Windows: Window position X coordinate not accurate

I want to get the (accurate) on-screen X and Y coordinates of a window (the client area). My problem is that I have to define a horizontal shift which has to be added onto the X coordinate to get the correct result:
#include <windows.h>
inline int get_title_bar_thickness(const HWND window_handle)
{
RECT window_rectangle, client_rectangle;
GetWindowRect(window_handle, &window_rectangle);
GetClientRect(window_handle, &client_rectangle);
const int height = window_rectangle.bottom - window_rectangle.top -
(client_rectangle.bottom - client_rectangle.top);
const int width = window_rectangle.right - window_rectangle.left -
(client_rectangle.right - client_rectangle.left);
return height - width / 2;
}
#define HORIZONTAL_SHIFT 8
/**
* Gets the window position of the window handle
* excluding the title bar and populates the x and y coordinates
*/
inline void get_window_position(const HWND window_handle, int* x, int* y)
{
RECT rectangle;
const auto window_rectangle = GetWindowRect(window_handle, &rectangle);
const auto title_bar_thickness = get_title_bar_thickness(window_handle);
if (window_rectangle)
{
*x = rectangle.left + HORIZONTAL_SHIFT;
*y = rectangle.top + title_bar_thickness;
}
}
The issue can be observed by moving the window programmatically:
const auto window_handle = FindWindow(nullptr, "Command Prompt");
SetWindowPos(window_handle, nullptr, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
I would expect this SetWindowPos() call to perfectly place the window into the upper left corner of my screen but there is some space left between the window and the screen border (exactly 8 pixels). Is there a way to assure that this horizontal offset is automatically considered? This might be related to laptops so how to make this behave as expected?
As commented by Castorix, the horizontal shift can be retrieved.
#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
inline int get_horizontal_shift(const HWND window_handle)
{
RECT window_rectangle, frame_rectangle;
GetWindowRect(window_handle, &window_rectangle);
DwmGetWindowAttribute(window_handle,
DWMWA_EXTENDED_FRAME_BOUNDS, &frame_rectangle, sizeof(RECT));
return frame_rectangle.left - window_rectangle.left;
}
The code is based on this post. The return value is 7 on my machine.

why do cx/cy from GetWindowRect(rcWindow2) differ from cx/cy fed into OnSize?

I want to get the cx and cy during OnInitDialog of a CDialog.
I can do this with the following code:
myDialog::OnInitDialog()
{
CRect rcWindow2;
this->GetWindowRect(rcWindow2);
CSize m_szMinimum = rcWindow2.Size();
int width = m_szMinimum.cx;
int height = m_szMinimum.cy;
}
However, the cx and cy in the OnInitDialog is not the same as cx and cy which got into OnSize:
void myDialog::OnSize(UINT nType, int cx, int cy)
From OnInitDialog: cx=417, cy=348
From OnSize : cx=401, cy=310
looks like might be the borders but i can't figure it out.
Suggestions as to how to get the same xy data in OnInitDialog as is fed into OnSize would be appreciated.
Inheritance:
myDialog -> CDialog -> CWnd
GetWindowRect returns window's Top-Left position in screen coordinates. Width and height of window includes border thickness and the height of the caption.
GetClientRect always returns zero for Top-Left corner. Width and height is the same values as OnSize.
While we are on the subject, this can also get confusing when it comes to moving child windows. Because SetWindowPos needs client coordinates, while GetWindowRect returns screen coordinates only. Screen/Client conversion will be needed like this:
void GetWndRect(CRect &rc, HWND child, HWND parent)
{
GetWindowRect(child, &rc);
CPoint offset(0, 0);
ClientToScreen(parent, &offset);
rc.OffsetRect(-offset);
}
Now we can move a button in dialog box:
CWnd *child = GetDlgItem(IDOK);
CRect rc;
GetWndRect(rc, child->m_hWnd, m_hWnd);
rc.OffsetRect(-5, -5);
child->SetWindowPos(0, rc.left, rc.top, 0, 0, SWP_NOSIZE);

c++ Xlib don't want to resize my window in height

I want to resize a window with Xlib so I made a function (she is inside a class) :
int setSizeAndMove(int top, int left, int width, int height)
{
XMoveResizeWindow(m_display, m_window_terminal, top, left, width, height);
return 1;
}
This function works fine. I have another function who return the size of the current window :
Rect getWindowSize() const
{
XWindowAttributes size_win;
XGetWindowAttributes(m_display, m_window_terminal, &size_win);
Rect size_return;
size_return.X = size_win.width;
size_return.Y = size_win.height;
return size_return;
}
(Rect is just a structur that contain int X & int Y)
My problem is when I do something like this :
setSizeAndMove(0, 0, getWindowSize().X + 10, getWindowSize().Y + 10);
The window correctly add 10 pixel to width but not to height, why ?
//Additional question with 0,0 the window isn't in the top left but something like 5,5.
Thanks for help.

C++ MFC button disappears at window resize

I have a Dialog in MFC C++ that has a CButton attached.
I want to modify OnSize() so that the button will anchor to bottom-left.
if (btn.m_hWnd) {
CRect winRect;
GetWindowRect(&winRect);
int width = winRect.right - winRect.left;
int height = winRect.bottom - winRect.top;
int x = width - wndWidth;
int y = height - wndHeight;
CRect rect;
btn.GetWindowRect(&rect);
rect.left += x;
rect.top += y;
btn.MoveWindow(&rect);
ScreenToClient(&rect);
btn.ShowWindow(SW_SHOW);
}
x and y are the difference of how much the window has changed and will be added to the button's start coordinates.
I am not sure about the last 2 commands (I might as well delete them) but then I run the program the button disappears.
I need to know a way to move the button by x and y.
The original code was using the wrong coordinate system for both the parent dialog, and the button.
A correct way to dock to the bottom left would be like this:
if (btn.m_hWnd) {
CRect winRect;
GetClientRect(&winRect);
CRect rect;
btn.GetWindowRect(&rect);
ScreenToClient(&rect);
int btnWidth = rect.Width();
int btnHeight = rect.Width();
rect.left = winRect.right-btnWidth;
rect.top = winRect.bottom-btnHeight;
rect.right = winRect.right;
rect.bottom = winRect.bottom;
btn.MoveWindow(&rect);
}
OR
if (btn.m_hWnd) {
CRect winRect;
GetClientRect(&winRect);
CRect rect;
btn.GetWindowRect(&rect);
ScreenToClient(&rect);
int btnWidth = rect.Width();
int btnHeight = rect.Width();
btn.SetWindowPos(NULL,winRect.right-btnWidth,winRect.bottom-btnHeight,0,0,SWP_NOSIZE|SWP_NOZORDER);
}
Basically, the answer should be to do ScreenToClient before MoveWindow!
Some more detail: You need to familiarize yourself with what function returns or uses client coordinates (and relative to what these client coordinates are) and which screen coordinates; this is one of the parts of MFC which can be really confusing. As to your question:
CWnd::GetWindowRect returns screen coordinates; CWnd::MoveWindow expects coordinates relative to the parent CWnd (or to the screen if it's a top level window). So before calling MoveWindow, you have to convert the rect returned by GetWindowRect to client coordinates of your parent window; suppose pParent is the CWnd * to the parent window of btn, then your moving code should look like this:
CRect rect;
btn.GetWindowRect(&rect);
pParent->ScreenToClient(&rect); // this line and it's position is important
rect.left += x;
rect.top += y;
btn.MoveWindow(&rect);
If you're in a method of the parent window (as I think you are, since you mention OnSize of the dialog), then just leave out the pParent->. The way you do ScreenToClient at the moment, it has no effect on MoveWindow, since it's executed after it!