Use tab and shift-tab to navigate out of a wxStyledTextCtrl within a wxPanel - wxwidgets

I am attempting to make a wxWidgets application, specifically poEdit, more accessible using the keyboard. There is a wxPanel that contains three controls; a combo box, a button, and a read only wxStyledTextCtrl. The problem is that once focus gets into the wxStyledTextCtrl it is impossible to move back to the other controls using the keyboard. I want to be able to tab out of the wxStyledTextCtrl back to the combo box. Thus far I have tried calling SetTabIndents(false) but that did not help.
Any ideas?

I have figured out the answer to my own question. I did end up sub classing the wxStyledTextCtrl class and overriding the MSWWindowProc function to customize the processing of the WM_GETDLGCODE message to clear the DLGC_WANTALLKEYS and DLGC_WANTTAB bits. The code I used is as follows.
The code I used to do this is as follows.
<myStc.h>
#include <wx/stc/stc.h>
class myWxStyledTextCtrl : public wxStyledTextCtrl
{
public:
DECLARE_DYNAMIC_CLASS(myWxStyledTextCtrl);
myWxStyledTextCtrl(
wxWindow* parent, wxWindowID id = wxID_ANY,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize, long style = 0,
const wxString& name = wxSTCNameStr);
myWxStyledTextCtrl();
void SetUseTabToNavigate(bool useTabToNavigate);
#ifdef __WXMSW__
// special Windows message handling
virtual WXLRESULT MSWWindowProc(
WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam);
#endif
DECLARE_EVENT_TABLE();
private:
bool m_useTabToNavigate;
};
</myStc.h>
<myStc.cpp>
#include "myStc.h"
IMPLEMENT_DYNAMIC_CLASS(myWxStyledTextCtrl, wxStyledTextCtrl);
BEGIN_EVENT_TABLE(myWxStyledTextCtrl, wxStyledTextCtrl)
END_EVENT_TABLE()
myWxStyledTextCtrl::myWxStyledTextCtrl(
wxWindow* parent, wxWindowID id /*= wxID_ANY*/,
const wxPoint& pos /*= wxDefaultPosition*/,
const wxSize& size /*= wxDefaultSize*/, long style /*= 0*/,
const wxString& name /*= wxSTCNameStr*/) :
wxStyledTextCtrl(parent, id, pos, size, style, name)
{
m_useTabToNavigate = false;
}
myWxStyledTextCtrl::myWxStyledTextCtrl() :
wxStyledTextCtrl()
{
m_useTabToNavigate = false;
}
void myWxStyledTextCtrl::SetUseTabToNavigate(bool useTabToNavigate)
{
m_useTabToNavigate = useTabToNavigate;
}
#ifdef __WXMSW__
WXLRESULT myWxStyledTextCtrl::MSWWindowProc(
WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
{
WXLRESULT ret = wxStyledTextCtrl::MSWWindowProc(nMsg, wParam, lParam);
if (!m_useTabToNavigate)
{
return ret;
}
if (nMsg == WM_GETDLGCODE)
{
ret &= ~(DLGC_WANTALLKEYS | DLGC_WANTTAB);
}
return ret;
}
#endif
</myStc.cpp>
I may figure out a solution that will work for other operating systems at some point in the future.

Related

Getting 0xC000041D crash in simple directX12 application

I have a simple Window class and I use a function for WM_PAINT that clears the render target view and presents the final image.so there's not much into it but I get a crash on line FLOAT clearColor[] = { 0.2f, 0.4f, 0.6f, 1.0f }; that says:0xC000041D: An unhandled exception was encountered during a user callback.
here's the window class:
class Win32Window : public WindowsWindow
{
public:
Win32Window(const WindowProps& props);
virtual ~Win32Window();
void OnUpdate() override;
unsigned int GetWidth() const override { return m_Data.Width; }
unsigned int GetHeight() const override { return m_Data.Height; }
void SetEventCallback(const EventCallbackFn& callback) override { m_Data.EventCallback = callback; }
void SetVSync(bool enabled) override;
bool IsVSync() const override;
virtual void* GetNativeWindow() const override { return m_Window; }
private:
HWND m_Window;
RECT m_WindowRect;
HINSTANCE m_hInst;
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
virtual void Init(const WindowProps& props);
virtual void Shutdown();
};
the definitions:
Win32Window::Win32Window(const WindowProps& props)
{
HZ_PROFILE_FUNCTION();
Init(props);
}
Win32Window::~Win32Window()
{
HZ_PROFILE_FUNCTION();
Shutdown();
}
void Win32Window::Init(const WindowProps& props)
{
m_hInst = GetModuleHandle(0);
m_Data.WideCharacterTitle = props.WideCharacterTitle;
m_Data.Width = props.Width;
m_Data.Height = props.Height;
HZ_CORE_INFO("Creating window {0} ({1}, {2})",props.StringTypeTitle, props.Width, props.Height);
WNDCLASSEXW windowClass = {};
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = &WndProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = m_hInst;
windowClass.hIcon = ::LoadIcon(m_hInst, NULL);
windowClass.hCursor = ::LoadCursor(NULL, IDC_ARROW);
windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
windowClass.lpszMenuName = NULL;
windowClass.lpszClassName = m_Data.WideCharacterTitle;
windowClass.hIconSm = ::LoadIcon(m_hInst, NULL);
static ATOM atom = ::RegisterClassExW(&windowClass);
assert(atom > 0);
int screenWidth = ::GetSystemMetrics(SM_CXSCREEN);
int screenHeight = ::GetSystemMetrics(SM_CYSCREEN);
RECT windowRect = { 0, 0, static_cast<LONG>(m_Data.Width), static_cast<LONG>(m_Data.Height) };
::AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, FALSE);
int windowWidth = windowRect.right - windowRect.left;
int windowHeight = windowRect.bottom - windowRect.top;
int windowX = std::max<int>(0, (screenWidth - windowWidth) / 2);
int windowY = std::max<int>(0, (screenHeight - windowHeight) / 2);
m_Window = ::CreateWindowExW(NULL, m_Data.WideCharacterTitle, m_Data.WideCharacterTitle, WS_OVERLAPPEDWINDOW, windowX, windowY, windowWidth, windowHeight, NULL, NULL, m_hInst, this);
assert(m_Window && "Failed to create window");
m_Context = GraphicsContext::Create(m_Window);
m_Context->Init();
::ShowWindow(m_Window, SW_SHOW);
::UpdateWindow(m_Window);
}
LRESULT Win32Window::MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
m_Context->RenderWindow();
break;
case WM_DESTROY:
::PostQuitMessage(0);
break;
default:
return ::DefWindowProcW(hwnd, message, wParam, lParam);
}
}
LRESULT Win32Window::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
Win32Window* instance;
if (message == WM_CREATE)
{
instance = (Win32Window*)(((LPCREATESTRUCT)lParam)->lpCreateParams);
instance->m_Window = hwnd;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)instance);
}
else
{
instance = (Win32Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
}
if (instance)
{
return instance->MainWndProc(hwnd, message, wParam, lParam);
}
return ::DefWindowProcW(hwnd, message, wParam, lParam);
}
void Win32Window::Shutdown()
{
DestroyWindow(m_Window);
m_Window = nullptr;
}
void Win32Window::OnUpdate()
{
m_Context->Update();
}
void Win32Window::SetVSync(bool enabled)
{
m_Data.VSync = enabled;
}
bool Win32Window::IsVSync() const
{
return m_Data.VSync;
}
m_Context is coming from the parent class, And also WindowProps that has some data for initializing the window .definition of m_Context->RenderWindow():
m_CommnadQueue = D3D12Core::Get().GetCommandQueue(D3D12_COMMAND_LIST_TYPE_DIRECT);
auto m_CommandList = m_CommnadQueue->GetCommandList();
m_CurrentBackBufferIndex = m_SwapChain->GetCurrentBackBufferIndex();
auto m_BackBuffer = D3D12Core::Get().m_BackBuffers[m_CurrentBackBufferIndex];
auto m_RTVDescriptorSize = D3D12Core::Get().GetDevice()->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
{
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_BackBuffer.Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
m_CommandList->ResourceBarrier(1, &barrier);
FLOAT clearColor[] = { 0.2f, 0.4f, 0.6f, 1.0f };
CD3DX12_CPU_DESCRIPTOR_HANDLE rtv(m_RTVDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), m_CurrentBackBufferIndex, m_RTVDescriptorSize);
m_CommandList->ClearRenderTargetView(rtv, clearColor, 0, nullptr);
}
{
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_BackBuffer.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
m_CommandList->ResourceBarrier(1, &barrier);
m_CommandList->Close();
ID3D12CommandList* const commandLists[] =
{
m_CommandList.Get()
};
D3D12Core::Get().m_FenceValues[m_CurrentBackBufferIndex] = m_CommnadQueue->ExecuteCommandList(m_CommandList);
UINT syncInterval = m_VSync;
UINT presentFlags = m_TearingSupport && !m_VSync ? DXGI_PRESENT_ALLOW_TEARING : 0;
m_SwapChain->Present(syncInterval, presentFlags);
m_CommnadQueue->WaitForFenceValue(D3D12Core::Get().m_FenceValues[m_CurrentBackBufferIndex]);
}
If there is anything else that I should put in question pls tell me.You can shout at me for my dumbness if you want to but help me pls,thx.
EDIT:
debug layer:
#ifdef _DEBUG
ComPtr<ID3D12Debug> debugInterface;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugInterface))))
{
debugInterface->EnableDebugLayer();
}
#endif
WaitForFenceValue after every Present is an extremely slow way to render in DirectX 12. You should generally cue 2-3 frames to the GPU rather than forcing the GPU to stall every frame. It is also highly problematic to have your WndProc block, which is what happens here. Your WndProc should always complete quickly as many hundreds of messages are processed a second for most applications.
Usually Direct3D rendering is not done within WM_PAINT. For a number of examples of common render loops, see GitHub.

Visual-C++ Win32 C++ Application. How do I print variables to the main screen?

I have tried C++11 methods and C methods to convert the string before printing and they either: Returned a string of the same characters or didn't print anything at all. I just wanted to know 3 things really: Is there a fault in the online tutorials and examples? Is there a fault in my interpretation and implementation of the code? What could I do differently to get this working?
// Yu-Gi-Oh! LP Calculator.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "Yu-Gi-Oh! LP Calculator.h"
#define MAX_LOADSTRING 100
#define LP UINT
#define ID CHAR
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Global Life Point Variables
struct Player {
LP Lp;
ID Name[MAX_LOADSTRING];
};
struct Player1, Player2, Player3, Player4;
// Forward declarations of functions included in this code module:
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TEMP: Remove these initializations when preferences are implemented.
Player1.Lp = 8000;
Player2.Lp = 8000;
Player3.Lp = 8000;
Player4.Lp = 8000;
LoadStringA(hInstance, (UINT)"John\0", Player1.Name, MAX_LOADSTRING);
LoadStringA(hInstance, (UINT)"Phil\0", Player2.Name, MAX_LOADSTRING);
LoadStringA(hInstance, NULL, Player3.Name, MAX_LOADSTRING);
LoadStringA(hInstance, NULL, Player4.Name, MAX_LOADSTRING);
// END TEMP
// TODO: Place code here.
// TODO: Load preferences file.
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_YUGIOHLPCALCULATOR, szWindowClass, MAX_LOADSTRING);
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_YUGIOHLPCALCULATOR));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_YUGIOHLPCALCULATOR);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassExW(&wcex);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_YUGIOHLPCALCULATOR));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
break;
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
RECT rect;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
GetClientRect(hWnd, &rect);
CHAR b[] = { NULL };
sprintf((char* const)&b, "%s", Player1.Name);
DrawTextA(hdc, b, ARRAYSIZE(b), &rect, DT_SINGLELINE | DT_CENTER | DT_TOP);
//TextOutA(hdc, rect.left, rect.top, s, ARRAYSIZE(Player1.Name));
SelectClipPath(hdc, RGN_AND);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
case WM_CLOSE:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
By changing:
#define ID CHAR
to:
#define ID LPCSTR
and changing:
ID Name[MAX_LOADSTRING];
to:
ID Name;
I made Player1.Name compatible with the type of the 2nd parameter of the DrawTextA function.
I then changed the 3rd parameter to -1 instead of using ARRAYSIZE(). This means that the function checks the size of the string itself? So the function is called like this:
DrawTextA(hdc, Player1.Name, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_TOP);
All I needed to do then was Initialize the string with my values instead of using LoadStringA so I changed:
LoadStringA(hInstance, (UINT)"John\0", Player1.Name, MAX_LOADSTRING);
to:
Player1.Name = "John";

MessageDialog - text change from c++ but no update on screen

I've managed to dynamically change several properties in a QML Item that contains a MessageDialog. I can read the newly set properties but they are not updated on the screen - it's still the text set by QML which is visible. I've even manually sent a textChanged() signal (see below) to no avail.
Any idea what I am missing? Here's what I do:
"ErrorDialog.qml":
Item{
id: baseItem
property string text: "myText"
property string title: "myTitle"
signal acceptedSignal()
onTextChanged: {
errorDialogItem.text=baseItem.text
}
MessageDialog {
id: errorDialogItem
objectName: "errorDialogItem"
text: baseItem.text
title: baseItem.title
onAccepted: {
acceptedSignal()
}
Component.onCompleted: visible=true
}
Now c++:
this->component = QSharedPointer<QQmlComponent>(new QQmlComponent(&this->engine));
QObject::connect(&engine, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));
component->loadUrl(QUrl(QStringLiteral("qrc:///main.qml")));
topLevel = QSharedPointer<QObject>(component->create());
window = qobject_cast<QQuickWindow *>(topLevel.data());
surfaceFormat = window->requestedFormat();
window->setFormat(surfaceFormat);
window->show();
QQmlComponent dialogComponent(&engine, QUrl(QStringLiteral("qrc:///ErrorDialog.qml")));
QObject *myObject = dialogComponent.create();
QQuickItem *item = qobject_cast<QQuickItem*>(myObject);
QQmlEngine::setObjectOwnership(item, QQmlEngine::CppOwnership);
qDebug()<<"title"<<item->property("title");
qDebug()<<"text"<<item->property("text");
QString newText="TEXT SET FROM C++";
qDebug()<<"setTextProp: "<<item->setProperty("text",newText);
//-> true
qDebug()<<"new text"<<item->property("text");
//-> correctly set!
property is set, but not visually changed.
So I fetch the embedded MessageDialog itself:
QObject* dialogObject=item->findChild<QObject*>("errorDialogItem");
QQuickItem* dialogItem=reinterpret_cast<QQuickItem*>(dialogObject);
item->setFlag(QQuickItem::ItemHasContents,true);
dialogItem->setFlag(QQuickItem::ItemHasContents,true);
I am doing everything I can currently think of, to get the text updated on Screen:
dialogItem->polish();
item->polish();
int methodIndex=item->metaObject()->indexOfMethod("textChanged()");
QMetaMethod method = item->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(item,Qt::DirectConnection);
//-->true
methodIndex=item->metaObject()->indexOfMethod("update()");
method = item->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(item,Qt::DirectConnection);
//-->true
methodIndex=dialogItem->metaObject()->indexOfMethod("textChanged()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection);
//-->true
methodIndex=dialogItem->metaObject()->indexOfMethod("windowGeometryChanged()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection);
//-->true
methodIndex=dialogItem->metaObject()->indexOfMethod("geometryChanged()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection);
//-->true
methodIndex=dialogItem->metaObject()->indexOfMethod("reset()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection);
//-->true
methodIndex=dialogItem->metaObject()->indexOfMethod("setVisible()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection,Q_ARG(bool,falseVar));
//-->false
methodIndex=dialogItem->metaObject()->indexOfMethod("setVisible()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection, Q_ARG(bool,trueVar));
//-->false
methodIndex=dialogItem->metaObject()->indexOfMethod("setText()");
method = dialogItem->metaObject()->method(methodIndex);
QString textStr = "a different text";
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection, Q_ARG(QString,textStr));
//-->false
methodIndex=dialogItem->metaObject()->indexOfMethod("polish()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection);
//-->false
Thanks #BaCaRoZzo, when creating that minimal example I've found out what the problem is. It is absolutely mandatory to do property changes before opening the Dialog, i.e. in a closed state. If I want to change things in a MessageDialog already opened, I have to close it, change the properties and then open it again. It is not sufficient to change properties and then to close and reopen (like a "redraw"). See
bool setItemProperty(QString role, T value)
in the .h file below.
Here is my working code, any further recommendations are gratefully appreciated. Note: the "Controller" class is just some class providing the QQmlApplicationEngine of the GUI.
C++-Class header: MessageDialog.h
#ifndef MESSAGEDIALOG_H
#define MESSAGEDIALOG_H
#include <QObject>
#include <QQuickItem>
#include <QDialog>
#include <QQmlApplicationEngine>
#include "src/controller/controller.h"
class MessageDialog : public QObject
{
Q_OBJECT
public:
enum StandardButton {
Ok = 0x00000400, // An "OK" button with AcceptRole.
Open = 0x00002000, // An "Open" button with AcceptRole.
Save = 0x00000800, // A "Save" button with AcceptRole.
Cancel = 0x00400000, // A "Cancel" button with RejectRole.
Close = 0x00200000, // A "Close" button with RejectRole.
Discard = 0x00800000, // A "Discard" button, DestructiveRole.
Apply = 0x02000000, // An "Apply" button with ApplyRole.
Reset = 0x04000000, // A "Reset" button with ResetRole.
RestoreDefaults = 0x08000000,//"Restore Defaults", ResetRole.
Help = 0x01000000, // A "Help" button with HelpRole.
SaveAll = 0x00001000, // A "Save All" button with AcceptRole.
Yes = 0x00004000, // A "Yes" button with YesRole.
YesToAll = 0x00008000, // A "Yes to All" button with YesRole.
No = 0x00010000, // A "No" button with NoRole.
NoToAll = 0x00020000, // A "No to All" button with NoRole.
Abort = 0x00040000, // An "Abort" button with RejectRole.
Retry = 0x00080000, // A "Retry" button with AcceptRole.
Ignore = 0x00100000, // An "Ignore" button with AcceptRole.
NoButton = 0x00000000 // An invalid button.
};
typedef QFlags<StandardButton> StandardButtons;
enum ButtonRole {
InvalidRole = -1, //button is invalid.
AcceptRole = 0, //accepted (e.g. OK).
RejectRole = 1, //rejected (e.g. Cancel).
DestructiveRole = 2,//destructive change
ActionRole = 3, //changes dialog.
HelpRole = 4, //request help.
YesRole = 5, //Yes"-like button.
NoRole = 6, //"No"-like button.
ApplyRole = 8, //applies current changes.
ResetRole = 7 //resets the dialog to default values.
};
enum Icon {
NoIcon = 0, // the message box does not have any icon.
Question = 4, // message is asking a question.
Information = 1, // message is nothing out of the ordinary.
Warning = 2, // message is a warning, but can be dealt with.
Critical = 3 // message represents a critical problem.
};
MessageDialog(Controller* controller,
QString title=QString(),
QString text=QString(),
QString informativeText=QString(),
QString detailedText=QString(),
StandardButtons buttons=QFlags<StandardButton>());
~MessageDialog();
void setText (const QString &text);
void setInformativeText (const QString &text);
void setDetailedText (const QString &text);
void setTitle(const QString &title);
bool open();
bool close();
void setStandardButtons(StandardButtons buttons);
void addButton(StandardButton button);
void setIcon(Icon icon);
StandardButton clickedButton();
void setModality(Qt::WindowModality modality);
int result();
StandardButton exec();
static void about(Controller* controller,
const QString &title,
const QString &text,
const QString &informativeText="",
const QString &detailedText="");
static StandardButton warning(
Controller* controller,
const QString &title,
const QString &text,
const QString &informativeText,
const QString &detailedText,
StandardButton button0 = NoButton,
StandardButton button1 = NoButton,
StandardButton button2 = NoButton,
StandardButton button3 = NoButton);
static MessageDialog::StandardButton information(
Controller* controller,
const QString &title,
const QString &text,
const QString &informativeText,
const QString &detailedText,
StandardButton button0 = NoButton,
StandardButton button1 = NoButton,
StandardButton button2 = NoButton,
StandardButton button3 = NoButton);
signals:
void buttonClicked(StandardButton standardButton);
void accepted();
void apply();
void discard();
void help();
void no();
void rejected();
void reset();
void yes();
public slots:
protected:
void initItem(Controller* controller);
void connectQMLSignals();
bool invokeMethod(QString methodSignature);
bool setStrings(
const QString &title,
const QString &text,
const QString informativeText,
const QString detailedText);
template <typename T>
bool setItemProperty(QString role, T value) {
Q_ASSERT(m_item);
bool wasOpen=m_isOpen;
close();
bool success;
success=m_item->setProperty(role.toLocal8Bit(),QVariant(value));
if(!success)
qDebug()<<"setProperty("<<role<<","<<value<<") failed.";
if (wasOpen) open();
return success;
}
QQmlApplicationEngine* m_engine;
QQuickItem* m_item;
bool m_isOpen;
StandardButtons m_standardButtons;
StandardButton m_result;
};
#endif // MESSAGEDIALOG_H
C++-Class implementation: MessageDialog.cpp
#include "messagedialog.h"
#include <QQuickItem>
#include <QQmlApplicationEngine>
MessageDialog::MessageDialog(
Controller *controller,
QString title,
QString text,
QString informativeText,
QString detailedText,
StandardButtons buttons)
{
Q_ASSERT(controller);
this->initItem(controller);
m_isOpen=false;
m_result=MessageDialog::NoButton;
this->setTitle(title);
this->setText(text);
this->setInformativeText(informativeText);
this->setDetailedText(detailedText);
this->setStandardButtons(buttons);
this->connectQMLSignals();
}
MessageDialog::~MessageDialog()
{
delete m_item;
}
void MessageDialog::setText(const QString &text)
{
setItemProperty("text",text);
}
void MessageDialog::setInformativeText(const QString &text)
{
setItemProperty("informativeText",text);
}
void MessageDialog::setDetailedText(const QString &text)
{
setItemProperty("detailedText",text);
}
void MessageDialog::setTitle(const QString &title)
{
setItemProperty("title",title);
}
void MessageDialog::setStandardButtons(StandardButtons buttons)
{
setItemProperty("standardButtons",buttons);
m_standardButtons=buttons;
}
void MessageDialog::addButton(MessageDialog::StandardButton button)
{
m_standardButtons|=button;
setItemProperty("standardButtons",m_standardButtons);
}
void MessageDialog::setIcon(MessageDialog::Icon icon)
{
setItemProperty("icon",icon);
}
MessageDialog::StandardButton MessageDialog::clickedButton()
{
int i=m_item->property("clickedButton").toInt();
return static_cast<MessageDialog::StandardButton>(i);
}
void MessageDialog::setModality(Qt::WindowModality modality)
{
setItemProperty("modality",modality);
}
int MessageDialog::result()
{
return this->clickedButton();
}
MessageDialog::StandardButton MessageDialog::exec()
{
QEventLoop loop;
connect(m_item, SIGNAL(accepted()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(apply()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(discard()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(help()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(no()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(rejected()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(reset()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(yes()),& loop,
SLOT(quit()),Qt::UniqueConnection);
invokeMethod("open()");
setModality(Qt::ApplicationModal);
loop.exec();
return this->clickedButton();
}
void MessageDialog::about(
Controller *controller,
const QString &title,
const QString &text,
const QString &informativeText,
const QString &detailedText)
{
MessageDialog dialog(controller);
dialog.setStrings(title,text,informativeText,detailedText);
dialog.setIcon(MessageDialog::Information);
dialog.setStandardButtons(Ok);
dialog.exec();
}
MessageDialog::StandardButton MessageDialog::warning(
Controller *controller,
const QString &title,
const QString &text,
const QString &informativeText,
const QString &detailedText,
MessageDialog::StandardButton button0,
MessageDialog::StandardButton button1,
MessageDialog::StandardButton button2,
MessageDialog::StandardButton button3)
{
MessageDialog dialog(controller);
dialog.setStrings(title,text,informativeText,detailedText);
dialog.setIcon(MessageDialog::Warning);
dialog.setStandardButtons(
StandardButtons(button0|button1|button2|button3));
dialog.exec();
return dialog.clickedButton();
}
MessageDialog::StandardButton MessageDialog::information(
Controller *controller,
const QString &title,
const QString &text,
const QString &informativeText,
const QString &detailedText,
MessageDialog::StandardButton button0,
MessageDialog::StandardButton button1,
MessageDialog::StandardButton button2,
MessageDialog::StandardButton button3)
{
MessageDialog dialog(controller);
dialog.setStrings(title,text,informativeText,detailedText);
dialog.setIcon(MessageDialog::Information);
dialog.setStandardButtons(
StandardButtons(button0|button1|button2|button3));
dialog.exec();
return dialog.clickedButton();
}
bool MessageDialog::open()
{
Q_ASSERT(m_item);
if (m_isOpen) return false;
m_isOpen=invokeMethod("open()");
return m_isOpen;
}
bool MessageDialog::close()
{
Q_ASSERT(m_item);
if (!m_isOpen) return false;
m_isOpen=!invokeMethod("close()");
return !m_isOpen;
}
bool MessageDialog::invokeMethod(QString methodSignature)
{
Q_ASSERT(m_item);
int methodIndex;
methodIndex=m_item->metaObject()->indexOfMethod(
methodSignature.toLocal8Bit());
QMetaMethod method = m_item->metaObject()->method(methodIndex);
return method.invoke(m_item,Qt::DirectConnection);
}
bool MessageDialog::setStrings(
const QString &title,
const QString &text,
const QString informativeText,
const QString detailedText)
{
bool success=true;
success &= this->setItemProperty("title",title);
success &= this->setItemProperty("text",text);
success &= this->setItemProperty("informativeText",informativeText);
success &= this->setItemProperty("detailedText",detailedText);
return success;
}
void MessageDialog::initItem(Controller *controller)
{
m_engine=controller->engine();
Q_ASSERT(m_engine);
QQmlComponent* myComponent=new QQmlComponent(
m_engine, QUrl(QStringLiteral("qrc:/MessageDialog.qml")));
Q_ASSERT(myComponent);
if (!myComponent->isReady()) {
qWarning("%s", qPrintable(myComponent->errorString()));
}
QObject *myObject = myComponent->create();
Q_ASSERT(myObject);
m_item = qobject_cast<QQuickItem*>(myObject);
Q_ASSERT(m_item);
QQmlApplicationEngine::setObjectOwnership(
m_item,QQmlApplicationEngine::CppOwnership);
}
void MessageDialog::connectQMLSignals()
{
connect(m_item, SIGNAL(accepted()),this, SIGNAL(accepted()));
connect(m_item, SIGNAL(apply()),this, SIGNAL(apply()));
connect(m_item, SIGNAL(discard()),this, SIGNAL(discard()));
connect(m_item, SIGNAL(help()),this, SIGNAL(help()));
connect(m_item, SIGNAL(no()),this, SIGNAL(no()));
connect(m_item, SIGNAL(rejected()),this, SIGNAL(rejected()));
connect(m_item, SIGNAL(reset()),this, SIGNAL(reset()));
connect(m_item, SIGNAL(yes()),this, SIGNAL(yes()));
}
And this is the correspondent MessageDialog.qml
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Dialogs 1.2
Item{
id: baseItem
property alias text: errorDialogItem.text
property alias detailedText: errorDialogItem.detailedText
property alias informativeText: errorDialogItem.informativeText
property alias title: errorDialogItem.title
property alias modality: errorDialogItem.modality
property alias standardButtons: errorDialogItem.standardButtons
property alias icon: errorDialogItem.icon
property alias clickedButton: errorDialogItem.clickedButton
property alias standardIconSource:
errorDialogItem.standardIconSource
signal accepted()
signal apply()
signal discard()
signal help()
signal no()
signal rejected()
signal reset()
signal yes()
function open() {
return errorDialogItem.open()
}
function close() {
return errorDialogItem.close()
}
MessageDialog {
id: errorDialogItem
objectName: "errorDialogItem"
onAccepted: baseItem.accepted()
onApply: baseItem.apply()
onDiscard: baseItem.discard()
onHelp: baseItem.help()
onNo: baseItem.no()
onRejected: baseItem.rejected()
onReset: baseItem.reset()
onYes: baseItem.yes()
}
}
I hope this might help somebody save time in the future.
Here's an alternative to SeDi's answer. It's not as thoroughly developed, but it's simple and easy to modify for your own needs.
Example implementation
MessageDialog::showCritcalError( myQmlEngine, "The sky is falling!" );
MessageDialog.h
#ifndef MESSAGEDIALOG_H
#define MESSAGEDIALOG_H
#include <QQmlEngine>
struct MessageDialog
{
static void showCritcalError( QQmlEngine *engine, const QString &message );
};
#endif // MESSAGEDIALOG_H
MessageDialog.cpp
#include "MessageDialog.h"
#include <QQmlComponent>
#include <QQuickItem>
// ---------------------------------
static const QString QML_RESOURCE_PREFIX( "qrc:/" );
static const QString DIALOG_QML( "MessgeDialog.qml" );
static const char *TITLE_PROP = "dialogTitle";
static const char *ICON_PROP = "dialogIcon";
static const char *TEXT_PROP = "dialogText";
static const char *VISIBLE_PROP = "dialogVisible";
static const QString INFO_DEFAULT_TITLE( "Information" );
static const QString WARNING_DEFAULT_TITLE( "Warning" );
static const QString CRITICAL_DEFAULT_TITLE( "Error" );
static const QString QUESTION_DEFAULT_TITLE( "Question" );
static const int NO_ICON = 0,
INFO_ICON = 1,
WARNING = 2,
CRITICAL_ICON = 3,
QUESTION_ICON = 4;
void showMessageDialog( QQmlEngine *engine,
const QString &title, const int icon, const QString &text )
{
QQmlComponent component( engine, QUrl( QML_RESOURCE_PREFIX + DIALOG_QML ) );
QQuickItem *item = qobject_cast<QQuickItem*>( component.create() );
item->setProperty( TITLE_PROP, title );
item->setProperty( ICON_PROP, icon );
item->setProperty( TEXT_PROP, text );
item->setProperty( VISIBLE_PROP, true ); // must do last after setting other properties
}
// ---------------------------------
void MessageDialog::showCritcalError( QQmlEngine *engine, const QString &message )
{ showMessageDialog( engine, CRITICAL_DEFAULT_TITLE, CRITICAL_ICON, message ); }
MessageDialog.qml (listed in .qrc in my use case)
import QtQuick 2.2
import QtQuick.Dialogs 1.1
Item {
property string dialogTitle: ""
property int dialogIcon: 0
property string dialogText: ""
property bool dialogVisible: false
MessageDialog {
id: messageDialog
title : dialogTitle
icon : dialogIcon
text : dialogText
visible : dialogVisible
modality: Qt.ApplicationModal
}
}

Win 32 API set window minimum size to keep text fully visible

I am currently a beginner in win 32 API and am making a sample program. The problem I face is I can't find a proper way to set the window's minimum size in order for the text inside it (centered) to be visible when the window gets at its minimum. The text is fully visible in all the other cases, except when I reach a certain "critical" size, after which the text is either seen partially or not seen at all.
I found how to change the width and height of the window, as shown here:
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage (0);
break;
case WM_GETMINMAXINFO:
((MINMAXINFO*)lParam)->ptMinTrackSize.x =100; //apply custom min width
((MINMAXINFO*)lParam)->ptMinTrackSize.y =100; //apply custom min height
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint (hwnd, &ps);
GetClientRect(hwnd,&rc);
DrawText (hdc, TEXT ("Sample text here"), -1, &rc,DT_SINGLELINE | DT_CENTER | DT_VCENTER ) ;
EndPaint (hwnd, &ps);
}
break;
default:
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
I think these lines should be changed, but I don't know what change needs to be made.
((MINMAXINFO*)lParam)->ptMinTrackSize.x =100; //apply custom min width
((MINMAXINFO*)lParam)->ptMinTrackSize.y =100; //apply custom min height
My idea is that instead explicit float values which are assigned to x and y members of the POINT structure, a function should be called, that determines the text's minimum width and height.
Any help would be appreciated.
Below is the full code of this program.
#if defined(UNICODE) && !defined(_UNICODE)
#define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
#define UNICODE
#endif
#include <tchar.h>
#include <windows.h>
#include <stdio.h>
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/* Make the class name into a global variable */
TCHAR szClassName[ ] = _T("CodeBlocksWindowsApp");
RECT rc;
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow)
{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
if (!RegisterClassEx (&wincl))
return 0;
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
_T("Code::Blocks Template Windows App"),
/* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
544, /* The programs width */
375, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
ShowWindow (hwnd, nCmdShow);
while (GetMessage (&messages, NULL, 0, 0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return messages.wParam;
}
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage (0);
break;
case WM_GETMINMAXINFO:
//window size/position is going to change
//apply custom min width/height 350,50
SIZE sz;
HDC hdc = GetDC( hwnd );
TCHAR* myString = TEXT("Sample Text!");
HFONT oldFont, myFont; //create your own font
//select your font into device context
oldFont = (HFONT)SelectObject( hdc, myFont );
//get font dimensions
GetTextExtentPoint32( hdc, myString, _tcslen( myString ), &sz );
((MINMAXINFO*)lParam)->ptMinTrackSize.x = sz.cx;
((MINMAXINFO*)lParam)->ptMinTrackSize.y = sz.cy;
//cleanup
SelectObject( hdc, oldFont );
DeleteObject( myFont );
ReleaseDC( hwnd, hdc );
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint (hwnd, &ps);
GetClientRect(hwnd,&rc);
DrawText (hdc, TEXT("Sample Text!"), -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_WORDBREAK ) ;
EndPaint (hwnd, &ps);
}
break;
default:
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
I apologize for the poor indentation.
I think that GetTextExtentPoint32 is what you want so you can calculate the text size and length. Here is the example showing how to use it.
Just in case your text gets bigger dimensions than your screen, you could add DT_WORDBREAK flag to your DrawText call-see the documentation.
You will need to create font and select it in your device context and CreateFontIndirect can help you-pay attention to the members of the LOGFONT structure so you can create font you wish. Here is one example of doing it.
Try something like this:
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint (hwnd, &ps);
//create your own font
HFONT oldFont, myFont;
// create logical font for menu
LOGFONT lf = { sizeof(lf) };
_tcscpy_s( lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"Microsoft Sans Serif" );
lf.lfHeight = -MulDiv( 12, GetDeviceCaps( hdc, LOGPIXELSY), 72);
lf.lfWeight = FW_HEAVY;
lf.lfItalic = FALSE;
lf.lfUnderline = FALSE;
myFont = CreateFontIndirect(&lf);
//select your font into device context
oldFont = (HFONT)SelectObject( hdc, myFont );
GetClientRect(hwnd,&rc);
DrawText (hdc, TEXT("Sample Text!"), -1, &rc,
DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_WORDBREAK ) ;
//cleanup
SelectObject( hdc, oldFont );
DeleteObject( myFont );
EndPaint (hwnd, &ps);
}
return 0L;
case WM_GETMINMAXINFO:
{
SIZE sz;
HDC hdc = GetDC( hwnd );
LPTSTR myString = TEXT( "Sample text here" );
//create your own font
HFONT oldFont, myFont;
// create logical font for menu
LOGFONT lf = { sizeof(lf) };
_tcscpy_s( lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"Microsoft Sans Serif" );
lf.lfHeight = -MulDiv( 12, GetDeviceCaps( hdc, LOGPIXELSY), 72);
lf.lfWeight = FW_HEAVY;
lf.lfItalic = FALSE;
lf.lfUnderline = FALSE;
myFont = CreateFontIndirect(&lf);
//select your font into device context
oldFont = (HFONT)SelectObject( hdc, myFont );
//get font dimensions
GetTextExtentPoint32( hdc, myString, _tcslen( myString ), &sz );
((MINMAXINFO*)lParam)->ptMinTrackSize.x = sz.cx;
((MINMAXINFO*)lParam)->ptMinTrackSize.y = sz.cy;
//cleanup
SelectObject( hdc, oldFont );
DeleteObject( myFont );
ReleaseDC( hwnd, hdc );
}
break;
If you have further questions leave a comment.
Best regards.

Compact Framework - Keep modal window in front of windows bar after closing CaptureCameraDialog

I am working on a windows mobile application. I have created a wizard that uses a modal window so that the windows bar is hidden. One of the wizard stages has requires a picture to be taken. After launching the CaptureCameraDialog, the windows bar appears and remains even after the CaptureCameraDialog is closed. Is there any way to bring my dialog form back in front of the windows bar?
I eventually managed to find some code on the web that did what I was looking for. Here it is:
public partial class myForm : Form
{
public myForm()
{
InitializeComponent();
this.GotFocus += delegate(object sender, EventArgs args)
{
//var intPtr = FindWindow("CaptureReturnForm", "");
SetForegroundWindow(GetFocus());
bool result = SHFullScreen(GetFocus(), SHFS_HIDESTARTICON |
SHFS_HIDETASKBAR | SHFS_HIDESIPBUTTON); // 0x0020);
};
}
[DllImport("coredll.dll")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("coredll.dll", EntryPoint = "SetForegroundWindow")]
private static extern int SetForegroundWindow(IntPtr hWnd);
[DllImport("coredll.dll")]
internal static extern IntPtr GetFocus();
[DllImport("aygshell.dll")]
internal static extern bool SHFullScreen(IntPtr hWnd, uint dwState);
const uint SHFS_SHOWTASKBAR = 0x1;
const uint SHFS_HIDETASKBAR = 0x2;
const uint SHFS_SHOWSIPBUTTON = 0x4;
const uint SHFS_HIDESIPBUTTON = 0x8;
const uint SHFS_SHOWSTARTICON = 0x10;
const uint SHFS_HIDESTARTICON = 0x20;
const int HWND_TOPMOST = -1;
const int HWND_NOTOPMOST = -2;
const uint SWP_SHOWWINDOW = 0x40;
const uint SM_CXSCREEN = 0x0;
const uint SM_CYSCREEN = 0x1;
private const int HHTASKBARHEIGHT = 26;
}