Calculating the correct width to resize image to display in a CListCtrl - visual-c++

At the moment I am having to fudge my code like this:
CRect rcList;
m_ListThumbnail.GetClientRect(rcList);
rcList.DeflateRect(25, 25);
// Use monitor 1 to work out the thumbnail sizes
CRect rcMonitor = m_monitors.rcMonitors.at(0);
m_iThumbnailWidth = rcList.Width();
double dHt = ((double)rcMonitor.Height() / (double)rcMonitor.Width()) * (double)m_iThumbnailWidth;
m_iThumbnailHeight = (int)dHt;
I fudge it by deflating the rectangle by 25. m_ListThumbnail is a CListCtrl and I am trying to render my thumbnails so that I do not need a horizontal scroll bar.
When I render the thumbnails of the monitors, I attempt to massage these thumbnail values (incomplete):
nWidth = m_iThumbnailWidth;
double dHt = ((double)rcCapture.Height() / (double)rcCapture.Width()) * (double)m_iThumbnailWidth;
nHeight = (int)dHt;
if (nHeight > m_iThumbnailHeight)
{
AfxMessageBox(L"Need to investigate!");
}
Where rcCapture is the size of the monitor.
If I remove the DeflateRect line, my window displays like this:
As you can see, it is note as I expected. There is a horizontal scroll bar and I have to resize quite a bit to see the thumbnail:
All I want to compute is a set of thumbnail dimensions so that the scaled down monitor image is going to fit in the CListCtrl. I don't really want the user to have to resize the window.
Update
With my adjusted code which now uses the primary monitor aspect ratio to work out the thumbnail sizes (as added above) renders the app with better whitespace:
That was the reason of the extra space at the bottom because the monitors were 16:9 and I was squishing into 4:3. So that is fixed.
But as you can see, using the CListCtrl client width is not sufficient.
Update
This is the rendering code:
// Set the mode first!
SetStretchBltMode(dcImage, COLORONCOLOR);
int iTop = (m_iThumbnailHeight - nHeight) / 2;
// Copy (and resize)
bRet = ::StretchBlt(dcImage, 0, iTop,
nWidth,
nHeight,
dcScreen.m_hDC,
rcCapture.left,
rcCapture.top,
rcCapture.Width(),
rcCapture.Height(), SRCCOPY | CAPTUREBLT);

The control renders the icon with a margin. When I used GetItemPosition function it indicated that the x value was 21. This is why my DeflateRect(25, 25) worked. But I don;t know how the CListCtrl computed that margin value.
Eventually I found out how to do this without deflating, by using the SetIconSpacing function. Like this:
m_ListThumbnail.SetIconSpacing(
CSize(m_iThumbnailWidth, ::GetSystemMetrics(SM_CXHSCROLL)));
Once the above has been done the window looks like this:
Things might be a little different when there are 3 or 4 monitor thumbnails, thus causing a vertical scroll bar. But I only have two monitors to test with.

Related

Using CMFCMenuButton::SizeToContent does not seem to work as I would like. Why?

I am perplexed about the SizeToContent method of the CMFCMenuButton control.
This is my dialog in the IDE:
As you can see, I have specifically made the button wider than the two on the far right.
I added the following code to OnInitDialog:
// Resize (if required)
const auto sizNewButton = m_btnReset.SizeToContent(true);
CRect rctButton;
m_btnReset.GetWindowRect(&rctButton);
if(sizNewButton.cx > rctButton.Width())
{
m_btnReset.SizeToContent();
}
Yet, when I run my application in English:
It has made it smaller. My application supports 50+ languages by using satellite DLLs and I was hoping to only resize to content if it was required. But it seems to resize it anyway. Have I missed a step here?
I have checked the properties for the control in the IDE and it is not set to auto resize:
I notice that the help documentation states:
The new size of the button is calculated to fit the button text, image, and arrow. The framework also adds in predefined margins of 10 pixels for the horizontal edge and 5 pixels for the vertical edge.
I had a look at my button:
Default size: 48 x 23 (the GeWindowRect result).
Calculated size: 57 x 23 (the SizeToContent result).
If I adjusted my code like this:
if((sizNewButton.cx - 10) > rctButton.Width())
That would bring it down to 47 and thus would not resize. I am assuming the code is not working right because of the padded margin that GetWindowRect knows nothing about.
Searched it, and found that the problem is MFC's CMFCMenuButton::SizeToContent() implementation in afxmenubutton.cpp:
CSize CMFCMenuButton::SizeToContent(BOOL bCalcOnly)
{
CSize size = CMFCButton::SizeToContent(FALSE); // <==== The culprit!!!
size.cx += CMenuImages::Size().cx;
if (!bCalcOnly)
{
SetWindowPos(NULL, -1, -1, size.cx, size.cy, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
}
return size;
}
That is, it calls the base implementation of SizeToContent() with the bCalcOnly parameter set to FALSE, which means it will also resize the control to just fit the text (without the drop-down arrow). This is less than required for the text plus the arrow, and of course the original size is lost.
A workaround can be get the (original) width, before the SizeToContent() call, and work with this instead of the new one:
CRect rctButton;
m_btnReset.GetWindowRect(&rctButton);
const auto nOrigWidth = rctButton.Width(); // Store the original width
const auto sizNewButton = m_btnReset.SizeToContent(true); // This resizes the control!!!
if (sizNewButton.cx > nOrigWidth) // Compare to the original width rather than the new one
m_btnReset.SizeToContent();
else // Restore original width
m_btnReset.SetWindowPos(NULL, -1, -1, nOrigWidth, sizNewButton.cy, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
Alternative Workaround:
Define a new CMFCMenuButton-based class, overriding SizeToContent() - in the implementation call the base CMFCButton::SizeToContent() with the bCalcOnly parameter passed by the caller, not with FALSE. Map the control to this class instead of CMFCMenuButton. That is use a class that fixes it. Too much of an overkill for just a workaround though.

Different wallpaper for each monitor in a multi-monitor setup in Windows 10

There are a number of questions and answers about setting wallpapers programmatically on multi-monitor setups in Windows, but I'm asking specifically for Windows 10 (and maybe Windows 8) because it seems to work differently from all the explanations I found.
Raymond Chen has an article "How do I put a different wallpaper on each monitor?" (https://devblogs.microsoft.com/oldnewthing/?p=25003), also quoted in Monitors position on Windows wallpaper. The core concepts is that Windows places the top-left corner of the provided bitmap at the top-left corner of the primary monitor, and wraps around to fill any desktop space to the left and/or above that. I understand that, I wrote a little program using that knowledge, and it works beautifully in Windows 7.
How it works: I create a bitmap that conceptually covers the whole desktop space, as the user sees it. I draw the contents of each monitor to that bitmap in its appropriate position (the program is written in C++ using VCL, but the principle remains the same in other programming environments):
TRect GetMonitorRect_WallpaperCoords(int MonitorNum)
{
Forms::TMonitor *PrimaryMonitor = Screen->Monitors[0];
Forms::TMonitor *Monitor = Screen->Monitors[MonitorNum];
// Get the rectangle in desktop coordinates
TRect Rect(Monitor->Left, Monitor->Top, Monitor->Left + Monitor->Width, Monitor->Top + Monitor->Height);
// Convert to wallpaper coordinates
Rect.Left += PrimaryMonitor->Left - Screen->DesktopLeft;
Rect.Top += PrimaryMonitor->Top - Screen->DesktopTop;
Rect.Right += PrimaryMonitor->Left - Screen->DesktopLeft;
Rect.Bottom += PrimaryMonitor->Top - Screen->DesktopTop;
return Rect;
}
std::unique_ptr<Graphics::TBitmap> CreateWallpaperBitmap_WallpaperCoords()
{
std::unique_ptr<Graphics::TBitmap> Bmp(new Graphics::TBitmap);
Bmp->PixelFormat = pf24bit;
Bmp->Width = Screen->DesktopWidth;
Bmp->Height = Screen->DesktopHeight;
// Draw background (not that we really need it: it will never be visible)
Bmp->Canvas->Brush->Style = bsSolid;
Bmp->Canvas->Brush->Color = clBlack;
Bmp->Canvas->FillRect(TRect(0, 0, Bmp->Width, Bmp->Height));
for (int MonitorNum = 0; MonitorNum < Screen->MonitorCount; ++MonitorNum)
{
TDrawContext DC(Bmp->Canvas, GetMonitorRect_WallpaperCoords(MonitorNum));
DrawMonitor(DC);
}
return Bmp;
}
(The draw context uses a coordinate translation rect so that the code int DrawMonitor function can draw in a rectangle like (0, 0, 1920, 1080) without having to wonder where in the full bitmap it is drawing, and with a clip rect so that DrawMonitor can not accidentally draw outside of the monitor it's drawing on).
Then I convert that bitmap to an image that will properly wrap around when placed at the top-left corner of the primary monitor (as Raymond Chen describes in his article):
std::unique_ptr<Graphics::TBitmap> ConvertWallpaperToDesktopCoords(std::unique_ptr<Graphics::TBitmap> &Bmp_WallpaperCoords)
{
std::unique_ptr<Graphics::TBitmap> Bmp_DesktopCoords(new Graphics::TBitmap);
Bmp_DesktopCoords->PixelFormat = Bmp_WallpaperCoords->PixelFormat;
Bmp_DesktopCoords->Width = Bmp_WallpaperCoords->Width;
Bmp_DesktopCoords->Height = Bmp_WallpaperCoords->Height;
// Draw Bmp_WallpaperCoords to Bmp_DesktopCoords at four different places to account for all
// possible ways Windows wraps the wallpaper around the left and bottom edges of the desktop
// space
Bmp_DesktopCoords->Canvas->Draw(Screen->DesktopLeft, Screen->DesktopTop, Bmp_WallpaperCoords.get());
Bmp_DesktopCoords->Canvas->Draw(Screen->DesktopLeft + Screen->DesktopWidth, Screen->DesktopTop, Bmp_WallpaperCoords.get());
Bmp_DesktopCoords->Canvas->Draw(Screen->DesktopLeft, Screen->DesktopTop + Screen->DesktopHeight, Bmp_WallpaperCoords.get());
Bmp_DesktopCoords->Canvas->Draw(Screen->DesktopLeft + Screen->DesktopWidth, Screen->DesktopTop + Screen->DesktopHeight, Bmp_WallpaperCoords.get());
return Bmp_DesktopCoords;
}
Then I install that bitmap as a wallpaper by writing the appropriate values in the registry and calling SystemParametersInfo with SPI_SETDESKWALLPAPER:
void InstallWallpaper(const String &Fn)
{
// Install wallpaper:
// There are 3 name/data pairs that have an effect on the desktop wallpaper, all under HKCU\Control Panel\Desktop:
// - Wallpaper (REG_SZ): file path and name of wallpaper
// - WallpaperStyle (REG_SZ):
// . 0: Centered
// . 1: Tiled
// . 2: Stretched
// - TileWallpaper (REG_SZ):
// . 0: Don't tile
// . 1: Tile
// We don't use the Wallpaper value itself; instead we use SystemParametersInfo to set the wallpaper.
// The file name needs to be absolute!
assert(Ioutils::TPath::IsPathRooted(Fn));
std::unique_ptr<TRegistry> Reg(new TRegistry);
Reg->RootKey = HKEY_CURRENT_USER;
if (Reg->OpenKey(L"Control Panel\\Desktop", false))
{
Reg->WriteString(L"WallpaperStyle", L"1");
Reg->WriteString(L"TileWallpaper", L"1");
Reg->CloseKey();
}
SystemParametersInfoW(SPI_SETDESKWALLPAPER, 1, Fn.c_str(), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
}
But when I test it in Windows 10, it doesn't work properly anymore: Windows 10 puts the wallpaper completely in the wrong place. Seeing as other people have asked questions about multi-monitor wallpapers in the past, I'm hoping there are people with experience of it on Windows 10.
As far as I can see, Windows 10 places the top-left corner of the provided bitmap at the top-left corner of the desktop space (by which I mean the bounding rectangle of all monitors), instead of the top-left corner of the primary monitor. In code, that means: I leave out the ConvertWallpaperToDesktopCoords step, and then it works fine as far as I can see.
But I can't find any documentation on this, so I don't know if this is officially explanation of how Windows 10 does it. Use with care. Also I don't know when this different behavior started: in Windows 10, or maybe earlier in Windows 8.

AndroidPlot - Labels and text

I am a non-developer product manager for an application built in both Android and iOS. We have a bar graph in iOS that provides text for the content of the graph. It displays Totals for each bar, and percentages for each segment of each bar.
In Android, using AndroidPlot (so I understand) we just display the bars with different color segments and no percent totals or totals. I am told by the developer that we can't show more.
I would display the images here, but stackoverflow tells me I don't have enough reputation points to do this. I have created a link to my dropbox with the images https://www.dropbox.com/sh/2uocm5bn79rerbe/AAB7s9QEEYIRIgXhKbUAaOyDa
Is it possible to use AndroidPlot to emulate this iOS chart or at least represent to same information to the end user?
Your developer is more or less correct but you have options. Androidplot's BarRenderer by default provides only an optional label at the top of each bar, which in your iOS images is occupied by the "available", "new", "used" and "rent" label. That label appears to be unused in your Android screenshot so one option would be to utilize those labels do display your totals.
As far as exactly matching the iOS implementation with Androidplot, the missing piece is the ability to add additional labels horizontally and vertically along the side of each bar. You can extend BarRenderer to do this by overriding it's onRender(...) method. Here's a link for your developer that shows where in the code he'll want to modify onRender(...).
I'd suggest these modifications to add the vertical labels:
Invoke Canvas.save(Canvas.ALL_SAVE_FLAG) to store the default orientation of the Canvas.
Use Canvas.translate(leftX, bottom) to center on the bottom left point of the bar
Rotate the Canvas 90 degrees using Canvas.rotate(90) to enable vertical text drawing
Draw whatever text is needed along the side of the plot; 0,0 now corresponds to the bottom left corner of the bar so start there when invoking canvas.drawText(x,y).
Invoke Canvas.restore() to restore the canvas' original orientation.
After implementing the above, adding horizontal "%" labels should be self evident but if you run into trouble feel free to ask more questions along the way.
UPDATE:
Here's a very basic implementation of the above. First the drawVerticalText method:
/**
*
* #param canvas
* #param paint paint used to draw the text
* #param text the text to be drawn
* #param x x-coord of where the text should be drawn
* #param y y-coord of where the text should be drawn
*/
protected void drawVerticalText(Canvas canvas, Paint paint, String text, float x, float y) {
// record the state of the canvas before the draw:
canvas.save(Canvas.ALL_SAVE_FLAG);
// center the canvas on our drawing coords:
canvas.translate(x, y);
// rotate into the desired "vertical" orientation:
canvas.rotate(-90);
// draw the text; note that we are drawing at 0, 0 and *not* x, y.
canvas.drawText(text, 0, 0, paint);
// restore the canvas state:
canvas.restore();
}
All that's left is to invoke this method where necessary. In your case it should be done once per BarGroup and should maintain a consistent position on the y axis. I added the following code to the STACKED case in BarRenderer.onRender(...), immediately above the break:
// needed some paint to draw with so I'll just create it here for now:
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTextSize(PixelUtils.spToPix(20));
drawVerticalText(
canvas,
paint,
"test",
barGroup.leftX,
basePositionY - PixelUtils.dpToPix(50)); // offset so the text doesnt intersect with the origin
Here's a screenshot of the result...sorry it's so huge:
Personally, I don't care for the fixed y-position of these vertical labels and would prefer them to float along the upper part of the bars. To accomplish this I modify my invocation of drawVerticalText(...) to look like this:
// needed some paint to draw with so I'll just create it here for now:
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTextSize(PixelUtils.spToPix(20));
// right-justify the text so it doesnt extend beyond the top of the bar
paint.setTextAlign(Paint.Align.RIGHT);
drawVerticalText(
canvas,
paint,
"test",
barGroup.leftX,
bottom);
Which produces this result:

fix a splash screen image to display in j2me

In my j2me App I have tried canvas which works great on Nokia phone but doesn't run on samsung. For that I have to switch to some FORM which in both cases works but only issue is of size, if I create smaller image to fit for both phone screens, one (samsung) shows that ok but other (nokia) leaves a lot more space and vice versa.
I need to have code that could stretch my image and just fix if to the screen size which I basically get by form.getHeight() and form.getWidth() property. I wonder if there is property of Image.createImage(width, height) then why doesn't it stretch it to the value I provide?
my code for that is below
try {
System.out.println("Height: " + displayForm.getHeight());
System.out.println("Width: " + displayForm.getWidth());
Image img1 = Image.createImage("/bur/splashScreen1.PNG");
img1.createImage(displayForm.getHeight(), displayForm.getWidth());
displayForm.append(new ImageItem(null, img1, Item.LAYOUT_CENTER, null));
} catch (Exception ex) {
}
Image
A single image will not fit all screens. But more will do.
The smaller logo image should be less than 96x54, as this is the smallest screen resolution. This image can be used up to the resolution of 128x128 without problems. With bigger resolutions it will look tiny, though.
The bigger logo image should be a bit bigger than 128x128 and can be used up to 240x320.
The code bellow gives as example of how to implement this.
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.Graphics;
class Splash extends javax.microedition.lcdui.Canvas {
Image logo;
Splash () {
if (getWidth() <= 128) {
// sl stands for Small Logo and does not need to have a file extension
// this will use less space on the jar file
logo = Image.createImage("/sl");
} else {
// bl stands for Big Logo
logo = Image.createImage("/bl");
}
}
protected void paint (Graphics g) {
// With these anchors your logo image will be drawn on the center of the screen.
g.drawImage(logo, getWidth()/2, getHeight()/2, Graphics.HCENTER | Graphics.VCENTER);
}
}
As seen in http://smallandadaptive.blogspot.com.br/2008/10/showing-splash.html
wonder if there is property of Image.createImage(width, height) then why doesn't it stretch it to the value I provide?
Parameters in this method have nothing to do with stretching, see API javadocs:
public static Image createImage(int width, int height)
Creates a new, mutable image for off-screen drawing.
Every pixel within the newly created image is white.
The width and height of the image must both be greater than zero.
Parameters:
width - the width of the new image, in pixels
height - the height of the new image, in pixels
Image class (API javadocs) has two more createImage methods that use parameters called "width" and "height" - one with six, another with four arguments but none of these has anything to do with stretching.
In createImage with six arguments, width and height specify size of the region to be copied (without stretching) from source image.
In method with four arguments, width and height specify how to interpret source ARGB array, without these it would be impossible to find out if, say, array of 12 values represents 3x4 image or 4x3. Again, this has nothing to do with stretching.

How can I get the screen width and length in android?

I want to display 9 buttons in the middle of the display, three on each row. In conclusion a big square that is composed from 9 little buttons displayed in the middle of the screen.
So I think I need to know the screen size to display buttons.
you only need to use Tablelayout or Linerlayout for this.but if need to know screen size it get as following :
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
If you're not in an Activity you can get the default Display via WINDOW_SERVICE:
WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();

Resources