I'm have some data output text boxes (text boxes with no border and with the same background as the rest of the window) that I'm trying to align with a standard edit control + spin button, to represent a column of numbers, one of which can be edited:
I can manually align these in the Delphi / C++Builder form designer, but when I then view the form on a different version of Windows or at a different DPI, the text is no longer right-justified, presumably because of differences in the spin button spacing, borders, etc.
I can use EM_GETMARGINS to determine the width of the spin button, but how can I determine the size of the edit control's margins and borders? I've tried various combinations of EM_POSFROMCHAR, ClientToScreen, GetSystemMetrics(SM_CXBORDER), GetSystemMetrics(SM_CXEDGE), and GetThemeMargins, but so far, I can't find a combination that works and makes sense.
More details:
Environment is Delphi / C++Builder XE2.
The data output controls are TEdits with BorderStyle bsNone.
The edit + spin button is a TJvSpinEdit. From viewing its source, it uses EM_SETMARGINS to allow space for its spin button.
Use the Win32 API GetWindowRect() and GetClientRect() methods. The bordering will be the difference between the two rectangles. That will only give you the bordering, though. There could be extra spacing inside the client area.
Related
Say you have a form that you can expand to the left to show additional controls:
Collapsed:
Expanded:
The simplest way to achieve this in Delphi is to use alRight as the primary anchor for all controls (instead of alLeft) and then simply adjust the width and X coordinate of the form. Either you can set the Width and Left properties individually, or you can use a function that sets them simultaneously, like
if FCollapsed then
SetWindowPos(Handle, 0, Left - Width, Top, 2 * Width, Height, 0)
else
SetWindowPos(Handle, 0, Left + Width div 2, Top, Width div 2, Height, 0)
The problem is that there is quite noticeable flickering in the always-visible part of the form (in this example, the buttons) while expanding or collapsing. Try it yourself!
It is possible for the operating system to resize the form to the left without any flickering at all -- just grab the left edge of the form using the mouse and drag the mouse to the left or right -- but I am unable to find any function in the Windows API that exposes this kind of resizing.
I have tried to use several different Windows API functions to resize and reposition the form, tried their various parameters (for instance, the SWP_* flags), tried LockWindowUpdate, WM_SETREDRAW, TForm.DoubleBuffered etc. to no avail. I also examined the possibility to use the WM_SYSCOMMAND SC_SIZE approach.
I am not yet sure if the problem lies at the OS level or the VCL level.
Any suggestions?
Edit: I am very surprised to see that this Q received close votes. Let me try to clarify:
Create a new VCL forms application.
Add a few buttons to the right side of the main form and a memo to the left. Set Anchors to [alTop, alRight] on all controls. On the OnClick handler of the buttons, add the following code:
if FCollapsed then
SetWindowPos(Handle, 0, Left - Width, Top, 2 * Width, Height, 0)
else
SetWindowPos(Handle, 0, Left + Width div 2, Top, Width div 2, Height, 0);
FCollapsed := not FCollapsed;
where FCollapsed is private boolean field of the form (initialized to false).
Now, click the buttons repeatedly. (Or give one of them keyboard focus and hold the Enter key for a few seconds.) You will probably notice that the region with the buttons on your monitor will not display a perfect still image, but will flicker. In addition, you might actually see 'ghosts' of the buttons to the left of the actual column of buttons.
I am unable to capture this millisecond flickering using screen capture, so instead I used a digital camera to record my screen:
https://privat.rejbrand.se/VCLFormExpandFlicker.mp4
In this video clip, it is apparent that the column of buttons isn't a static image on the screen; instead, for a few milliseconds each time the form is resized, this region is something else than it should be. It is equally apparent that there is a 'ghost' column of buttons to the left.
My question is if there is any reasonably simple way to get rid of these visual artefacts (that at least to me are very visible even if you expand/collapse the form a single time).
On my Windows 10/Delphi 10.1 computer at work, the form is resized in a perfect manner when I drag its left-most edge using the mouse: the unaffected client area of the form is perfectly static on the monitor. However, on my Windows 7/Delphi 2009 PC at home, I do see that there is a lot of repositioning going on when I do this.
I can provide some insight about why you see ghost images of the other half of your UI and possibly a way to stop it. The ghost image indicates that someone is copying your client area pixels (and copying them to the wrong place, always flush-left in your window) before you have a chance to redraw them with the correct pixels.
There are likely two different, overlapping sources of these ghost pixels.
The first layer applies to all Windows OSes and comes from a BitBlt inside SetWindowPos. You can get rid of that BitBlt in several ways. You can create your own custom implementation of WM_NCCALCSIZE to tell Windows to blit nothing (or to blit one pixel on top of itself), or alternately you can intercept WM_WINDOWPOSCHANGING (first passing it onto DefWindowProc) and set WINDOWPOS.flags |= SWP_NOCOPYBITS, which disables the BitBlt inside the internal call to SetWindowPos() that Windows makes during window resizing. This has the same eventual effect of skipping the BitBlt.
However, Windows 8/10 aero adds another, more troublesome layer. Apps now draw into an offscreen buffer which is then composited by the new, evil DWM.exe window manager. And it turns out DWM.exe will sometimes do its own BitBlt type operation on top of the one already done by the legacy XP/Vista/7 code. And stopping DWM from doing its blit is much harder; so far I have not seen any complete solutions.
For sample code that will break through the XP/Vista/7 layer and at least improve the performance of the 8/10 layer, please see:
How to smooth ugly jitter/flicker/jumping when resizing windows, especially dragging left/top border (Win 7-10; bg, bitblt and DWM)?
Since you have multiple child windows, the situation is even a little more complicated. The BitBlt type operations I mentioned above happen on your whole top-level window as a whole (they treat the window as one set of pixels regardless of how many windows are underneath, and regardless of CLIPCHILDREN). But you need to have windows move atomically so that on the next redraw they are all positioned correctly. You may find BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos useful for that (but only go there if the above tricks do not work).
I'm trying to emulate Xcode's toolbar controls to show/hide the Navigator and Inspector:
...but without the bottom pane (only left and right: two segments)
I screen-captured the icons from Xcode's UI and traced them in an image editing application. The resources for the left pane are:
#1x:
(20x20 #72 dpi)
#2x:
(40x40 #72 dpi, although using 20x20 #144 dpi seems to make no difference)
The right-pane counterparts are identical, but flipped horizontally.
All rhe resources are stored in the asset catalogue, as follows:
I dropped a segmented control on the toolbar, to create a toolbar item with a segmented control inside it, and set the image attribute for each segment (0 and 1).
Image Scaling for both segments is set to "Proportionally Down". The segment control has segment width "Fixed" checked, with a width of 48 for both segments. The toolbar item has Minimum Size of (83 x 25) and Maximum Size of (100 x 28).
The icons display correctly on the storyboard (Interface Builder).
However, when I run the app, I can not get the icon images to display appropriately.
If I launch my app on a retina monitor, no icon is displayed on either segment.
If I move the window to the external, non-retina monitor, both icons are displayed.
If I remove the one of the two image sets from thew catalogue and run the app, the other icon is correctly displayed! (on either monitor)
If I further set the same, remaining image for both segments, they display correctly!
If I leave both image sets in the project, but reset the Image field in one of the segments to empty, the other icon isn't displayed eihter!
What on Earth is going on??
I have put a sample project on GitHub that reproduces the issue.
Edit: Just to make sure, I extracted the resources from the compiled app binary using the cartool command line utility (as explained in this answer), and all 4 images are there at the right sizes...
Solution: As suggested by Ivan's answer below, I switched to using vector graphics (PDF) for the icons. I downloaded the trial version of Acorn and recreated my icons at 1x size, then exported as PDF.
To avoid blurring at the scaled up size of #2x at runtime, I had to make sure all coordinates in the editor were integers, and also check the box for "Snap to pixels" in the Vector Shapes inspector for each shape layer:
(Happy Ending)
$ git commit -m "Fix toolbar icons for good (PDF)"
According to my experience, using of bitmaps in toolbar is troublesome. You can try to target exactly recommended resolutions to possibly avoid some problems: https://developer.apple.com/macos/human-interface-guidelines/icons-and-images/custom-icons/
However, the cleanest way would be to use vector (pdf) icons, as they simply work as intended.
I import Spotfire graphics into Powerpoint quite frequently. Spotfire has its own specific color palette, which aren't the standard colors used in powerpoint, at least I don't think so.
I often must create my own legend or for other reasons match the spotfire color palette, and I do this by entering the RGB codes for the spotfire colors. I would like to do this one time and have the spotfire color palette always available in powerpoint without having to re-type.
I do not think I want to use a color theme, because I want my colors to stay consistent if I end up using different templates (themes). That is, I don't want to call spotfire default blue "Accent 1", because if I change background templates (themes) I think it will overwrite Accent 1 with the new template's Accent 1.
So I want a color palette that is always available to me regardless of what theme I choose.
Any thoughts?
You're dismissing themes for all the right reasons. They wouldn't work for what you're after. You'd pretty much need to buy or write an add-in to do what you want.
For example, it might install n buttons on the toolbar/ribbon, where n = the number of colors you need on your palette. When the button is clicked it sets the fill, for example, of the currently selected shape/shapes to the appropriate color.
You could have different sets of buttons for fill, outline etc, or have the code figure out whether the user has pressed, eg the CTRL key. Click = set the fill, CTRL+Click = set the outline.
Because I was curious I decided to attempt to create a simple Add-In that will allow you to select a chart, series in the chart, and then apply colors.
You can download from Google Docs (revised link)
https://docs.google.com/file/d/0B1v0s8ldwHRYMFFPZ29FNmI0TkE/edit?usp=sharing
The file is saved as a PPTM to expose the code modules. Save As a PPAM and load the Add-in; it will be available from the Add-Ins command bar. I have tested briefly and seems to be working.
Here's the nuts & bolts of it:
First declared several custom colors as Public Const variables. These can be modified using the long value (converted from RGB) to suit whatever you need.
The macro requires that the selection be a Shape, and further that the Shape .HasChart = True. There is some logic to trap these conditions.
A user form has a ComboBox that populates with a list of Series from the selected chart, and 8 CommandButtons colored for each of the defined colors, will send that color to the chosen series.
You could add additional CommandButtons and colors as needed, or tweak the existing code to suit your specific needs.
Although the slide templates have a default color theme attached to them, you can switch slide templates and still use any XML color scheme at your disposal.
I'm using the ssOption control (Sheridan 3d Option control) in VB6.
In Windows 98 the text area background color is the same color as the background color around the Option Circle, and that color is the default form color. So the Option button appears to be transparent.
There is no Background color property and on Windows XP the background color of the text area is a different color from the background color around the Option circle.
Any ideas as to why this would happen? The control's wrapper is in Threed32.ocx and I have the same version of it in the Windows\system32 directory on both the Win98 and WinXP systems.
Why might it behave differently on 98 vs XP?
Any ideas on a fix?
SSOption sets it background to the Windows Button Face on Windows XP. This the same background you get when you make a new form. You will need to use a frame or another type of enclosure that has a background of button face if you want to use it on a multi-colored form. Otherwise use VB6's Option button.
The advantages of the SSOption is the ability to display it's text in a 3D raised or inset format. This really only works well using the default button face color which is why it is hard coded into the control. It also has better formatting of the text when the option button is to the right of the text.
If you can't use a enclosing frame or panel then you have a tedious alternative. You can make an VB6 option with no text. If you are using the 3D font. Then you can use two labels to achieve the same effect. Make the bottom white (or top depending on raised vs inset) and offset by one pixel or 15 twips.
You can use the ZoomIn tool if you installed VB6 as part of the Visual Studio 6 package to make sure it is right.
If you are using it for the Alignment. Then you can fiddle with the width of the VB6 native option control until it looks right or make the option with no text and use a label.
Threed32.ocx is ancient - it was designed for VB4. I would replace it with the built-in VB6 option control.
Alex is right. Threed32.ocx is old and has a number of problems. It's not supported on Vista, it grabs the focus when it's made visible, it's hard to upgrade to VB.NET - there are more. For my company these are strong enough to outweigh the extra functionality it gives - we're droppping it from all our programs.
I'm using a VB6 PictureBox on my User Control. I set the PictureBox's picture, I set the BorderStyle to 0, and I set the BackColor to the User Control's BackColor. The idea is that I want a "floating" icon. However, I want that icon to appear clickable when the mouse hovers over it.
Two questions:
Which events do I use? MouseMove seems to be the closest to a "MouseOver" event. Are there any cleaner alternatives?
How should I change the style? I've tried a few things, but none of them quite look right.
MouseMove is the correct event in VB6. You'll have to do some work to manually detect when the mouse leaves the client area cleanly. (My experiments in this world, lo those many years ago, always found implementing this behavior to be tricky.)
For changing the style, I'd recommend using GDI to: (a) shift the image one pixel up and to the left; (b) draw a single pixel line in the ButtonHighlightColor along the top and left edges; and (c) draw a single pixel line in the ButtonShadowColor along the bottom and right edges. This is trickier than it sounds, particularly in VB6, so ultimately I'd recommend ...
That you look at vbAccelerator's toolbar controls. They're free, and they'll probably get you most of where you want to be. (And yes, they're "classic" VB -- that is, VB6.)