Setting default color in Windows Forms - windows

I'm creating a simple GUI using Powershell and Windows Forms for a set of scripts I have written.
I've generated a bunch of buttons in the GUI and I'm currently in the process of adding styles to my buttons.
$Button1 = New-Object System.Windows.Forms.Button
Is there anyway to set the below set of lines as a global/default setting of sorts for all buttons?
$Button1.Cursor = [System.Windows.Forms.Cursors]::Hand
$Button1.BackColor = '#CCCC99'
$Button1.Font = New-Object System.Drawing.Font("Verdana",10,[System.Drawing.FontStyle]::Bold)
To give you an idea, what I'm doing now is adding the block of text for every button.
$Button1.BackColor = '#CCCC99'
$Button2.BackColor = '#CCCC99'
$Button3.BackColor = '#CCCC99'
etc...
I'm pretty sure there's a better and more efficient way to do this. Can anyone point me to the right direction?
I expect all buttons to look pretty much the same.
Thanks in advance.

You could loop through all of the buttons after they have been created and set their properties, like TheMadTechnician suggests…
But there is a better way. Think object-oriented programming. You have a Button class, and you want to change its default properties. In fact, you want all of your buttons to have those new properties. So really, what you want is a custom control that is like a button but slightly different.
Well, what do you know? There's a linguistic way to express that:
public class MyBeautifulButton : System.Windows.Forms.Button
{
public MyBeautifulButton()
{
// Set default properties here...
}
}
You can even go one fancier and override the specific properties, setting the appropriate attributes, to change their default values.
Then, instead of creating System.Windows.Forms.Button objects in your PowerShell code, you will create MyBeautifulButton objects.
Although I must say that I don't think the result will be terribly beautiful. The BackColor property of a button is one of those that I don't think should have ever been provided. Button controls are designed to be drawn using the system theme, which specifies the colors for you. It also allows the users to customize the colors as desired. Application-specified colors usually result in a visually jarring and downright ugly UI. Don't let your app stick out like a sore thumb. Buttons are utility controls. Consistency is key. Remember that GUI applications are not web pages.

Why not just apply that to all buttons after you add them to the form? Something along the lines of:
$MyForm.Controls | Where{$_.GetType().Name -eq "Button"} | ForEach{$_.BackColor = '#CCCC99'}

Related

How do I set program title and icon in Clutter toolkit?

I have recently been learning how to program with the Clutter GUI toolkit. One thing I haven't been able to figure out is how to set the programs title and icon for the window manager.
As illustrated in the image below, Gnome Shell says that the program name is "Unknown" and that the program does not have an icon.
So, how do I do this?
you cannot do this from Clutter: the windowing system API inside Clutter only allows basic operations.
if you want proper integration in a windowing system you should use Clutter-GTK, and embed a ClutterStage into a Gtk application.
In theory, you can do that in this way:
let stage = Clutter.Stage.get_default ();
let gdkWind = ClutterGdk.get_stage_window (stage);
// The list most containt icons in different sizes.
let list = [GdkPixbuf.Pixbuf.new_from_file("test.png")];
gdkWind.set_icon_list(list);
//The next line not work
gdkWind.set_title("This title is not added");
In practice, you only will can load the icon and the windows title, but not the task bar title for the windows. The set_title won't work as Gdk.Window reference say it will (https://people.gnome.org/~gcampagna/docs/Gdk-3.0/Gdk.Window.set_title.html). Is then a Clutter issue, because is not a GDK "special case". But well is not working.

Big problems with MFC/WinAPI

I need to create a SDI form with a formview that has two tabs, which encapsulate multiple dialogs as the tab content. But the form has to have a colored background.
And things like these makes me hate programming.
First, I tried CTabControl, via resource editor, tried different things, but the undocumented behavior and the quirks with no answers led me into a roadblock.
After many hours of searching, I found that there is a control called property sheet, which is actually what I need.
Some more searching later, I found that property sheet can even be actually embedded onto CFormView like so: http://www.codeguru.com/Cpp/controls/propertysheet/article.php/c591
And that the dialog classes derived from CPropertyPage can be directly added as pages via AddPage method of CPropertySheet.
Great! Not quite so... Some of the controls didn't worked, and were not created, ran into weird asserts. Turns out the DS_CONTROL style was missing from the dialogs. Found it completely accidentaly on Link, no word about that on MSDN!!!! Property page must have: DS_3DLOOK | DS_CONTROL | WS_CHILD | WS_TABSTOP, and can have: DS_SHELLFONT | DS_LOCALEDIT | WS_CLIPCHILDREN styles! Not any other, which are created by default with resource editor. Sweet, super hidden information for software developers!
The quote in comments on that page: "OMG. That's where that behavior came from...
It turns out that the PlaySound API relied on that behavior when playing sounds on 64bit machines." by Larry Osterman, who as I understand works for Microsoft for 20 years, got me laughing out loud.
Anyway, fixed that, the dialog-controls(CPropertyPages) are created as expected now, and that part looks something remotely promising, but the next part with color is dead end again!
Normally you override WM_CTLCOLOR, check for control ID or hwnd and supply the necessary brush to set the color you need. Not quite so with CPropertySheet, the whole top row stays gray! For CTabCtrl it somehow works, for CPropertySheet it doesn't.
Why? Seems that the CPropertySheet is kinda embedded inside CTabControl or something, because if I override WM_ERASEBKGND, only the internal part changes the color.
Now it seems that there is a GetTabControl() method in the CPropertySheet, that returns the actual CTabCtrl* of the CPropertySheet. But since it's constructed internally, I can't find how to override it's WM_CTLCOLOR message processing.
There seems to be a way to subclass the windowproc, but after multiple tries I can't find any good source on how to do it. SubclassWindow doc on MSDN says: "The window must not already be attached to an MFC object when this function is called."?! What's that?
I tried creating a custom CCustomTabCtrl class based on CTabCtrl via MFC wizard, created an instance of it, called SubclassWindow from one of the CCustomPropertySheet handlers to override the internal CTabCtrl, but nothing works, mystical crashes deep inside MFC.
Tried setting WindowLong with GCL_HBRBACKGROUND for the internal CTabCtrl, nothing changed.
And worst of all, I can't find any sort of useful documentation or tutorials on the topic.
Most I can find is how to ownerdraw the tab control, but this is seriously wrong on so many ways, I want a standard control behavior minus background color, I don't want to support different color schemes, windows versions, IAccesible interfaces and all this stuff, and none of the ownerdraw samples I've seen can get even 10% of all the standard control behavior right. I have no illusion that I will create something better, I wont with the resources at hand.
I stumbled upon this thread, and I can't agree with the author more: http://arstechnica.com/civis/viewtopic.php?f=20&t=169886&sid=aad002424e80121e514548d428cf09c6 owner draw controls are undocumented PITA, that are impossible to do right, and there is NULL information on MSDN to help.
So is there anything I have missed or haven't tried yet? How to change the top strip background color of the CPropertySheet? Anyone?
Your only option is to ownerdraw the tab control. It's not that hard. Well, it is frustrating because MFC doesn't tell you how to make the necessary Win32 calls.
In your CPropertySheet-derived class, overwrite OnInitDialog() and add:
GetTabControl()->ModifyStyle(0,TCS_OWNERDRAWFIXED);
This puts your CPropertySheet-derived class in charge of drawing the tab control. Add a handler for WM_DRAWITEM (OnDrawItem) and change backgroundColor and textColor to match whatever colors you wanted. Code for OnDrawItem follows:
void CPropSht::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
if (ODT_TAB != lpDrawItemStruct->CtlType)
{
CPropertySheet::OnDrawItem(nIDCtl, lpDrawItemStruct);
return;
}
// prepare to draw the tab control
COLORREF backgroundColor = RGB(0,255,0);
COLORREF textColor = RGB(0,0,255);
CTabCtrl *c_Tab = GetTabControl();
// Get the current tab item text.
TCHAR buffer[256] = {0};
TC_ITEM tcItem;
tcItem.pszText = buffer;
tcItem.cchTextMax = 256;
tcItem.mask = TCIF_TEXT;
if (!c_Tab->GetItem(c_Tab->GetCurSel(), &tcItem )) return;
// draw it
CDC aDC;
aDC.Attach(lpDrawItemStruct->hDC);
int nSavedDC = aDC.SaveDC();
CBrush newBrush;
newBrush.CreateSolidBrush(backgroundColor);
aDC.SelectObject(&newBrush);
aDC.FillRect(&lpDrawItemStruct->rcItem, &newBrush);
aDC.SetBkMode(TRANSPARENT);
aDC.SetTextColor(textColor);
aDC.DrawText(tcItem.pszText, &lpDrawItemStruct->rcItem, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
aDC.RestoreDC(nSavedDC);
aDC.Detach();
}
Thank you for this solution but...
The above solution works well with one tab, but when you have multiple tabs it seems rename the wrong tabs. I needed to change the if statement for GetItem to:
if (!c_Tab->GetItem(lpDrawItemStruct->itemID, &tcItem )) return;
Needed lpDrawItemStruct->itemID to get the tabs named correctly

chrome-like status bar in qt

I'm not big on creating GUI's, and generally my philosophy is: I don't create them, or I make them as simple as possible (and convince myself that it's better for usability :)
For my current project, I'm using Qt from Python (PyQt), and I want to start adding some GUI elements without cluttering the interface.
My idea is to create these elements as sort of floating-shaped-widgets that only appear when necessary; pretty much like the status bar (and find bar) in chrome.
Is there any standard api that enables creating this kind of interface?
This is not very complicated. If you want something like the status bar in Chrome you just need to have a QFrame at the bottom of your windows and show or hide it when you need it.
You have 2 options here, add is as part of your window layout so all the items move up when it is shown. Or you can have if floating, so it will be shown on top of the items. For the second option you need to create the QFrame with the window as parent and then in the window resizeEvent set the geometry of the frame.
This is an example of the second approach:
void MyWindow::resizeEvent(QResizeEvent* event)
{
frame.setGeometry(0, this->height() - frame.sizeHint().height(), this->width(), frame.sizeHint().height());
}
I hope this helps.

Textbox anchored to a form on all 4 sides not displayed properly

I'm running into a problem trying to anchor a textbox to a form on all 4 sides. I added a textbox to a form and set the Multiline property to True and the Anchor property to Left, Right, Up, and Down so that the textbox will expand and shrink with the form at run time. I also have a few other controls above and below the textbox.
The anchoring works correctly in Visual Studio 2005 (i.e. I can resize the form and have the controls expand and shrink as expected), but when I run the project, the bottom of the textbox is extended to the bottom of the form, behind the other controls that would normally appear beneath it. This problem occurs when the form loads, before any resizing is attempted. The anchoring of the textbox is correct for the top, left, and right sides; only the bottom is malfunctioning.
Has anybody heard of this and if so, were you able to find a solution?
Thanks!
UPDATE:
Here is some of the designer code as per Greg D's request (I am only including the stuff that had to do with the textbox itself, not the other controls):
Friend WithEvents txtRecommendationText1 As System.Windows.Forms.TextBox
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Me.txtRecommendationText1 = New System.Windows.Forms.TextBox
' ...snip...
'txtRecommendationText1
Me.txtRecommendationText1.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _
Or System.Windows.Forms.AnchorStyles.Left) _
Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
Me.txtRecommendationText1.Location = New System.Drawing.Point(4, 127)
Me.txtRecommendationText1.Multiline = True
Me.txtRecommendationText1.Name = "txtRecommendationText1"
Me.txtRecommendationText1.Size = New System.Drawing.Size(223, 149)
Me.txtRecommendationText1.TabIndex = 10
End Sub
ANOTHER UPDATE:
The textbox I originally posted about was not inherited from a baseclass form (although it was added to a custom User Control class; I probably should have mentioned that earlier), but I recently ran into the same problem on a totally unrelated set of controls that were inherited from a baseclass form. It's easy to blame these problems on possible bugs in the .NET framework, but it's really starting to look that way to me.
Is your Form localized? Check the resource files for an entry with Textbox.Size, delete is and reset the size.
Is your Form inherited and is the Textbox on the baseform? Try setting the Textbox's access modifier to Protected or Public.
Have you implemented custom resize logic? Turn it off and see if the problem is still there.
Have you entered a Textbox.MinimumSize/MaximumSize? Remove or change the value.
It might also be a combination of these things...
Does the form snap back to the expected layout when you resize it after it's been initialized weirdly? Also, have you set a Height or MinimumHeight/MaximumHeight property for the text box?
If possible, a few snippets from the designer code might be useful. :)
One possibility that I've run into in the past is DPI. If you're running/testing your code on a machine with a different DPI setting than the machine that you're developing on, you may observe some strange things.
The anchor functionality essentially establishes a fixed distance between the edge of a control and the edge of the control's parent. Is your textbox embedded within another control (e.g., a panel) that doesn't have its anchors properly set? Right clicking on the text box in the designer should pop up a menu that lets you select any controls that exist underneath it, also.
Does your program include any custom resize logic, or does it modify the size of the textbox programmatically outside of designer-generated code? That might also result in weird behavior. I've assumed maintenance for a number of pieces of software at my organization where the original developers spent a great deal of time implementing (buggy) resize logic that I had to tear out so that I could just let the designer-generated code do the work for me.
The textbox I originally posted about was not inherited from a baseclass form (although it was added to a custom User Control class; I probably should have mentioned that earlier), but I recently ran into the same problem on a totally unrelated set of controls that were inherited from a baseclass form. It's easy to blame these problems on possible bugs in the .NET framework, but it's really starting to look that way to me.
It's very likely because of the 'AutoScaleMode' property being set in InitializeComponent(). Try setting it to 'None' and see if that fixes it. I've had these problem a couple of times now.

Changing Win32 menu colors

Is there a way to change the colors used by plain Win32 menus (background, text, and highlight) for a single process, without using SetSysColors?
(SetSysColors does a global change, which is bad, and if you crash or forget to set the colors back with SetSysColors again before exiting, they will not be restored until you logout.)
The SetMenuInfo() API is your friend. It lets you apply any brush to paint your menu's background.
Something along these lines should solve your problem:
MENUINFO mi = { 0 };
mi.cbSize = sizeof(mi);
mi.fMask = MIM_BACKGROUND|MIM_APPLYTOSUBMENUS;
mi.hbrBack = hBrush;
HMENU hMenu = ::GetMenu(hWnd);
SetMenuInfo(hMenu, &mi);
If I believe your comment to Rob, it is for a skinned application, with special look and feel. So the way to go is probably indeed, as ferek points out (in an unfriendly way...) to use owner-drawn menus: you will be able to define precisely their look.
I have to ask, why? Adopting the regular Windows look-and-feel is good; it means users can be confident that there are consistent elements in your user interface, onto which they can map their experience using other software for the platform.
[I'm probably preaching to the converted, of course, but I thought I'd make the point so anyone who reads an answer for this doesn't start making all their menus sky-blue-pink 'cause it looks pretty.]

Resources