on 11-15-2012 6:04 PM
I'm using PB 11.5, in case that is relevant to the following.
So, response windows can't be resizable in PB, but I wanted them to be. I found a solution for that online somewhere (sorry, I seem to have lost the link). First you declare the following:
// Unicode declarations, - used to set Response windows to be resizable, which PB doesn't allow
function long GetWindowLongW (long hWindow, integer nIndex) Library "user32.dll"
function long SetWindowLongW (long hWindow, integer nIndex, long dwNewLong) library "user32.dll"
The you call a function with the following code, in the window's Open event:
long ll_Styles
n_cst_numerical lnv_num // PFC resize service
constant long WS_THICKFRAME = 262144
constant long WS_CAPTION = 12582912
constant long WS_SYSMENU = 524288 // N.B. This corresponds to ControlMenu in PB's General Window settings, it never seems to
// work for Response window, and in fact having ControlMenu checked on the actual
// Response window causes it to not be resizable!
/*
constant int SWP_NOSIZE = 1
constant int SWP_NOMOVE = 2
constant int SWP_NOZORDER = 4
constant int SWP_FRAMECHANGED = 32
*/
ll_styles = GetWindowLongW(handle(THIS), -16)
if ll_styles <> 0 then
ll_styles = lnv_num.of_BitWiseOr(ll_styles, WS_THICKFRAME + WS_CAPTION)
SetWindowLongW(handle(THIS), -16, ll_styles)
// According to the docs, calling the following is required after adding the WS_SYSMENU in SetWindowLong.
// So I was hoping it would fix the fact that it makes the window non-rezisable. But it doesn't, unfortunately.
// SetWindowPos(handle(THIS), 0, 0, 0, 0, 0, SWP_FRAMECHANGED + SWP_NOMOVE + SWP_NOSIZE + SWP_NOZORDER)
end if
As you can perhaps see from my comments, there's a problem, which is that doing this doesn't work if Control Menu is checked in the window's painter (which is what puts the "X" at the top right, for closing the window). Adding in WS_SYSMENU to ll_styles should turn that back on, but it doesn't. (I can't immediately recall whether it does nothing, or also makes the window not be resizable.)
I don't suppose anybody has any bright ideas how to fix this? It's a bit weird in my app, which is mostly response windows, some of which are resizable and some of which aren't, that only the non-resizable ones have the control menu's "X".
Thanks.
Here's what we use. This is the of_setresizable function that takes an argument that determines whether or not a sizegrip should show at the bottom right corner of the window:
ulong ll_style, hMenu, hWnd, ll_newstyle
hWnd = Handle( this )
//Turn on the instance variable that is used elsewhere to see if the window is resizeable
ib_resizeable = TRUE
//Get the original size of the window, which we will prevent the user from sizing the window
//less than
il_orig_width = this.width
il_orig_height = this.height
//Get the current window style
ll_style = GetWindowLong(handle(this), GWL_STYLE)
IF this.ControlMenu THEN
//You have to include the MINIMIZEBOX attribute to get the controls to show
ll_newstyle = ll_style + WS_THICKFRAME + WS_MINIMIZEBOX
ELSE
ll_newstyle = ll_style + WS_THICKFRAME
END IF
IF ll_style <> 0 THEN
IF SetWindowLong ( hWnd, GWL_STYLE, ll_newstyle ) <> 0 THEN
IF this.ControlMenu THEN
//Get a handle to the system menu
hMenu = GetSystemMenu( hWnd, FALSE )
IF hMenu > 0 THEN
InsertMenu( hMenu, 1, MF_BYPOSITION + MF_STRING, &
SC_MAXIMIZE, "Maximize" ) ;
InsertMenu( hMenu, 1, MF_BYPOSITION + MF_STRING, &
SC_RESTORE, "Restore" ) ;
//The Size menu option has to be added to allow the resize gripper to work
//if there is a control menu
InsertMenu( hMenu, 1, MF_BYPOSITION + MF_STRING, &
SC_SIZE, "Size" ) ;
DrawMenuBar( hWnd )
END IF
END IF
//Force a repaint
SetWindowPos ( hWnd, 0, 0, 0, 0, 0, &
SWP_NOSIZE + SWP_NOMOVE + SWP_NOZORDER + SWP_FRAMECHANGED )
this.SetRedraw( TRUE )
//Track whether or not the size grip should show
ib_show_szgrip = ab_showgrip
END IF
END IF
We use this in an event mapped to pbm_getminmaxinfo:
//If this isn't a resizeable response window, don't bother with this
IF NOT ib_resizeable THEN RETURN
//Since we're resizable, we want to make sure that the user doesn't try to resize the
//window smaller than it's original size
s_MinMaxInfo lstr_MinMaxInfo
//Populate the structure
GetMinMaxInfo(lstr_MinMaxInfo, MinMaxInfo, 40)
//Determine the minimum size of the window (the original size)
lstr_MinMaxInfo.ptMinTrackSize.x = UnitsToPixels(il_orig_width, XUnitsToPixels!)
lstr_MinMaxInfo.ptMinTrackSize.y = UnitsToPixels(il_orig_height, YUnitsToPixels!)
//Now set the Min/Max info
SetMinMaxInfo(MinMaxInfo,lstr_MinMaxInfo,40)
return 0
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Bruce, I tried pretty much exactly your code, but first of all, although I have TitleBar checked in the painter for my window, unless I add in WS_CAPTION to the styles, the title bar disappears entirely. And even with it added in (and your code otherwise the same), I never get a control menu or "X" at the top right (which is what I really want).
The only other thing that might be different is I'm doing all this in an ancestor window of the actual window. (Maybe you were too and just didn't mention it.)
I will also study Chris' code that he pointed me at.
That code is from our w_reponse window, the ancestor of all our response windows. Works great for us. I can only think you might have a constant value or external declaration wrong.
Did you see the comment in the code about about "You have to include the MINIMIZEBOX attribute to get the controls to show" and include that code?
Here's the constants we're using
CONSTANT int GWL_STYLE = -16
CONSTANT uint SWP_NOSIZE = 1
CONSTANT uint SWP_NOMOVE = 2
CONSTANT uint SWP_NOZORDER = 4
CONSTANT uint SWP_FRAMECHANGED = 32
CONSTANT ulong WS_SYSMENU = 524288
CONSTANT ulong WS_THICKFRAME = 262144
CONSTANT ulong WS_MINIMIZEBOX = 65536
CONSTANT ulong WS_MAXIMIZEBOX = 131072
CONSTANT uint SC_RESTORE = 61728
CONSTANT uint SC_MAXIMIZE = 61488
CONSTANT uint SC_MINIMIZE = 61472
CONSTANT uint SC_SIZE = 61440
CONSTANT uint MF_BYCOMMAND = 0
CONSTANT uint MF_STRING = 0
CONSTANT uint MF_BYPOSITION = 1024
Those are exactly the values I had, Bruce, with one exception: You seem to have swapped the values of WS_MINIMIZEBOX and WS_MAXIMIZEBOX, according to my copy of WinUser.h. So I tried using your value - no change in the behaviour. Without WS_CAPTION, there's no title bar, and with it, there's still no control menu or "X".
Here are my local external function declarations, in case you can see something wrong with them:
function long GetWindowLongW (long hWindow, integer nIndex) Library "user32.dll"
function long SetWindowLongW (long hWindow, integer nIndex, long dwNewLong) library "user32.dll"
function long SetWindowPos(long hWnd, long hWndInsertAfter, int newX, int newY, int newWidth, &
int newHeight, uint uFlags) library "user32.dll"
function ulong GetSystemMenu(ulong hWnd, long bRevert) library "user32.dll"
function long InsertMenuW(uLong hMenu, uint uPosition, uint uFlags, uint uIDNewItem, String lpNewItem) library "user32.dll"
function long DrawMenuBar(ulong hWnd) library "user32.dll"
(Yes, I could use aliases to get rid of the "W" in the some of the function names, but obviously, that's not part of the problem.)
I have some differences, though I don't know that they're material:
function boolean SetWindowPos(long hWnd, long hWndInsertAfter, int newX, int newY, int newWidth, &
int newHeight, long uFlags) library "user32.dll"
function ulong GetSystemMenu(ulong hWnd, boolean bRevert) library "user32.dll"
function boolean InsertMenuW(uLong hMenu, uint uPosition, uint uFlags, uint uIDNewItem, String lpNewItem) library "user32.dll"
function boolean DrawMenuBar(ulong hWnd) library "user32.dll"
What probably is material is this:
IF this.ControlMenu THEN
//You have to include the MINIMIZEBOX attribute to get the controls to show
ll_newstyle = ll_style + WS_THICKFRAME + WS_MINIMIZEBOX
ELSE
ll_newstyle = ll_style + WS_THICKFRAME
END IF
Since I've got the values of WS_MINIMIZEBOX and WS_MAXIMIZEBOX reversed, you probably want to change that to:
IF this.ControlMenu THEN
//You have to include the MAXIMIZEBOX attribute to get the controls to show
ll_newstyle = ll_style + WS_THICKFRAME + WS_MAXIMIZEBOX
ELSE
ll_newstyle = ll_style + WS_THICKFRAME
END IF
OK, Bruce, I finally figured out what was wrong. I was using a version of n_cst_numerical from the PFC to do the bitwise or-ing of the styles, whereas your code was just adding in the new styles.
When I tried just adding them in, your code worked perfectly.
When I dug into n_cst_numerical, the problem was that the of_BitwiseOr() function I was calling was expecting a long arg, and returning a long. When I looked at the current actual window styles value, pre-modification, it was not within the range of long values, but it was in the range of ulong values. When I hacked of_BitwiseOr to accept and return ulong values instead, it gave the same results as the simple addition in your code.
FWIW, Chris, your object that has similar functions for bitwise OR also uses longs, not ulongs, so presumably could run into the same problems if used on window styles. (Though perhaps there are other sensible uses where you would prefer to be working on signed longs.)
Just one remaining question - I really don't want the user to be able to maximize these windows, just size them a bit. (Largely because in almost all cases, I'm only sizing the main DW on the window vertically, not horizontally, so maximizing just puts in a lot of white space on the right.) So, any way to have this working, but remove the max box at the top right?
MANY THANKS!
Glad you got it resolved.
You could probably tweak the code in the GetMinMaxInfo event. What I have just makes sure they don't make the window too small. You should be able to set the ptMaxTrackSize (like the current code sets the ptMinTrackSize) to prevent the window from being sized over a set limit.
That forces a repaint of the window. If it works fine for you without it, comment it out. You can always uncomment it if you run into problems later. It may only be required if you're using another control as a size grip (which we do). Hard to tell at this point, I wrote that code back in 2004....
If you dont want the Maximize button to show, remove or comment out the portion in red below.
It doesn't max a lot of sense to me why removing the WS_MINIMIZEBOX also removes the Maximize box. But it seems to work. The X still appears in the corner.
IF this.ControlMenu THEN
//You have to include the MINIMIZEBOX attribute to get the controls to show
ll_newstyle = ll_style + WS_THICKFRAME //+ WS_MINIMIZEBOX
ELSE
ll_newstyle = ll_style + WS_THICKFRAME
END IF
@ Bruce -
In your event mapped to pbm_getminmaxinfo - What are your external declarations for the GetMinMaxInfo and SetMinMaxInfo functions?
Maybe:
subroutine GetMinMaxInfo ( ref str_minmaxinfo d, long s, long l ) library 'kernel32.dll' alias for RtlMoveMemory
subroutine SetMinMaxInfo ( long d, str_minmaxinfo s, long l ) library 'kernel32.dll' alias for
RtlMoveMemory
Do they work on 64 bit machines?
Actually, the point of that was to use the setting of the control menu on the window to determine whether the min/max buttons show. Otherwise the IF doesn't serve a purpose with that code commented out.
That is, you don't need to comment out the code. Just don't check the ControlMenu option in the window painter and you won't get the buttons.
Also note that my sample has the values for WS_MINIMIZEBOX and WS_MAXIMIZEBOX reversed. That's why the code passes WS_MINIMIXEBOX here.
Hi Dan;
This is all done already in my Foundation Classes for PowerBuilder framework that is free and available for download from the SourceForge website. I have also adapted this code-line for Appeon as well so Web applications can have re-sizable response dialogs as well.
You can download the framework from here: http://sourceforge.net/projects/stdfndclass
Feel free to use the framework or copy off what you need for this task.
HTH
Regards ... Chris
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Dan;
That's all you need to do. What you guys are doing is "way over kill" IMHO. Also, my framework allows a minimum and maximum size and will hold the window dialog to those dimensions during a resize operation.
FWIW: The ancestor code is basically ...
IF ib_resizeable = TRUE THEN
// Lets get ready to make it Resizable!
IF ib_valid_environment = TRUE then
long ll_styles
ll_styles = GetWindowLong (handle(THIS), -16)
IF ll_styles <> 0 THEN
nc_numerical_master lo_numerical
lo_numerical = CREATE nc_numerical_master
lo_numerical.of_register (THIS)
ll_styles = lo_numerical.of_bitwiseor (ll_styles, ws_thickframe)
Destroy lo_numerical
SetWindowlong (Handle (THIS), -16, ll_styles)
END IF
End IF
END IF
The key to the whole resizability is to be able to OR the current window's style onto the existing state of the dialog. My frameworks "numerical" object - written in pure PowerScript BTW - has implemented OR, AND, xOR and xAND plus SLL and SLR low level bit manipulations to make this easy to implement.
You might want to download the sample OrderEntry application from SourceForge as well and see the response dialog resizability feature in full operation within the initial Logon screen interaction.
HTH & good luck in your endevour!
Regards .. Chris
Chris, I have definitely tried code exactly equivalent to yours, where all I do is OR in WS_THICKFRAME and set it back to the window. I can't explain why it works for you and not for me, but when I do it, the window does definitely NOT become resizable. All that changes is that when the mouse hovers over the edges of the window, the cursor changes to a resizing cursor. But if you then click on that edge and try to drag to resize, nothing happens.
I really need to leave this problem now and move on to other things. Maybe you and Bruce could discuss why or whether the other parts of the code are required, and if you figure it out, post that back here.
If you look at the parts of the code where this test is done:
IF this.ControlMenu THEN
You'll see that 90% of the code (or so) handles the TRUE case. If you look at what happens for FALSE, it's basically the same thing Chris' code does.
That is, Chris' code is fine if you don't want to have a control menu on the window. If you do, you need the additional code we use.
Hi Dan;
It does not work for me 100% either. I am working on refining my framework code - so far I have dynamic Min/Max controls working with resizing. A little better ... will let you know when I have it 100%.
BTW: Bruce ... thanks $!M though for your sharing your approach. I think that the optimal implementation is somewhere in between what we have all discussed.
Regards ... Chris
I Googled and found the original article this was based on:
There is a similar article and solution at http://eric.aling.tripod.com/PB/tips/pbtip39.htm, but he advises only adding in WS_THICKFRAME and optionally WS_SYSMENU to the styles. When I try that (with both), there is no title bar on the window at all, let alone a control menu!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
75 | |
10 | |
10 | |
7 | |
7 | |
6 | |
6 | |
6 | |
5 | |
4 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.