I have a button on an MFC dialog. How can I make the text bold?
class CYourDialog : CDialog
{
public:
virtual BOOL OnInitDialog(); // override
private:
CButton m_button;
CFont m_font;
};
BOOL CYourDialog::OnInitDialog()
{
__super::OnInitDialog();
CFont* font = m_button.GetFont();
LOGFONT logFont;
font->GetLogFont(&logFont);
logFont.lfWeight = FW_BOLD;
m_font.CreateFontIndirect(&logFont);
m_button.SetFont(&m_font);
return TRUE; // => system will set input focus to the first control item in the dialog box; (0 => you set the focus to a control of your choice)
}
You can create a new CFont and call WM_SETFONT on the button. Something like this:
// note: m_font is a class variable of type CFont
m_font.CreateFont(10, 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 0, 0, "Arial")
GetDlgItem(IDC_BUTTON1)->SendMessage(WM_SETFONT, WPARAM(HFONT(font)), 0);
Related
I am having some difficulties in correctly populating a CListCtrl with thumbnails of monitor displays.
On the right of my CDialog I have a static control and I render the image on a white canvas like this:
void CCenterCursorOnScreenDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
if (nIDCtl == IDC_STATIC_MONITOR && !m_imgPreview.IsNull())
{
// Set the mode
SetStretchBltMode(lpDrawItemStruct->hDC, HALFTONE);
// Wipe the canvas
FillRect(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)));
// Get canvas rectangle
const CRect rectCanvas(lpDrawItemStruct->rcItem);
// Calculate ratio factors
const float nRatioImage = m_imgPreview.GetWidth() / static_cast<float>(m_imgPreview.GetHeight());
const float nRatioCanvas = rectCanvas.Width() / static_cast<float>(rectCanvas.Height());
// Calculate new rectangle size
// Account for portrait images (negative values)
CRect rectDraw = rectCanvas;
if (nRatioImage > nRatioCanvas)
rectDraw.SetRect(0, 0, rectDraw.right, static_cast<int>(rectDraw.right / nRatioImage));
else if (nRatioImage < nRatioCanvas)
rectDraw.SetRect(0, 0, static_cast<int>((rectDraw.bottom * nRatioImage)), rectDraw.bottom);
// Add a margin
rectDraw.DeflateRect(5, 5);
// Move to center
const CSize ptOffset = rectCanvas.CenterPoint() - rectDraw.CenterPoint();
rectDraw.OffsetRect(ptOffset);
// Add a black frame
FrameRect(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)));
// Draw
m_imgPreview.Draw(lpDrawItemStruct->hDC, rectDraw);
return;
}
CDialogEx::OnDrawItem(nIDCtl, lpDrawItemStruct);
}
The above works beautifully:
But I have problems with the CListCtrl versions of the images. For instance, I am losing the colouring as you can see.
My CImageList is created like this:
m_ImageListThumb.Create(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, ILC_COLOR32, 0, 1);
m_ListThumbnail.SetImageList(&m_ImageListThumb, LVSIL_NORMAL);
I then create all the thumbnails by calling DrawThumbnails() in OnInitDialog:
void CCenterCursorOnScreenDlg::DrawThumbnails()
{
int monitorIndex = 0;
m_ListThumbnail.SetRedraw(FALSE);
for (auto& strMonitor : m_monitors.strMonitorNames)
{
CImage img;
CreateMonitorThumbnail(monitorIndex, img, true);
CBitmap* pImage = new CBitmap();
pImage->Attach((HBITMAP)img);
m_ImageListThumb.Add(pImage, nullptr);
CString strMonitorDesc = m_monitors.strMonitorNames.at(monitorIndex);
strMonitorDesc.AppendFormat(L" (Screen %d)", monitorIndex + 1);
m_ListThumbnail.InsertItem(monitorIndex, strMonitorDesc, monitorIndex);
monitorIndex++;
delete pImage;
}
m_ListThumbnail.SetRedraw(TRUE);
}
The CreateMonitorThumbnail function:
BOOL CCenterCursorOnScreenDlg::CreateMonitorThumbnail(const int iMonitorIndex, CImage &rImage, bool bSmall)
{
const CRect rcCapture = m_monitors.rcMonitors.at(iMonitorIndex);
// destroy the currently contained bitmap to create a new one
rImage.Destroy();
auto nWidth = rcCapture.Width();
auto nHeight = rcCapture.Height();
if (bSmall)
{
nWidth = THUMBNAIL_WIDTH;
nHeight = THUMBNAIL_HEIGHT;
}
// create bitmap and attach it to this object
if (!rImage.Create(nWidth, nHeight, 32, 0))
{
AfxMessageBox(L"Cannot create image!", MB_ICONERROR);
return FALSE;
}
// create virtual screen DC
CDC dcScreen;
dcScreen.CreateDC(_T("DISPLAY"), nullptr, nullptr, nullptr);
// copy the contents from the virtual screen DC
BOOL bRet = FALSE;
if (bSmall)
{
CRect rt(0, 0, nWidth, nHeight);
//::FillRect(rImage.GetDC(), rt, static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)));
bRet = ::StretchBlt(rImage.GetDC(), 0, 0,
nWidth,
nHeight,
dcScreen.m_hDC,
rcCapture.left,
rcCapture.top,
rcCapture.Width(),
rcCapture.Height(), SRCCOPY | CAPTUREBLT);
}
else
{
bRet = ::BitBlt(rImage.GetDC(), 0, 0,
rcCapture.Width(),
rcCapture.Height(),
dcScreen.m_hDC,
rcCapture.left,
rcCapture.top, SRCCOPY | CAPTUREBLT);
}
// do cleanup and return
dcScreen.DeleteDC();
rImage.ReleaseDC();
return bRet;
}
Ideally I want to have exactly the same kind of visual image as on the right, but obviously resized down. How do I fix this?
I simplified the converting from CImage to CBitmap but it made no difference:
void CCenterCursorOnScreenDlg::DrawThumbnails()
{
int monitorIndex = 0;
// Stop redrawing the CListCtrl
m_ListThumbnail.SetRedraw(FALSE);
// Loop monitor info
for (auto& strMonitor : m_monitors.strMonitorNames)
{
// Create the thumbnail image
CImage monitorThumbnail;
CreateMonitorThumbnail(monitorIndex, monitorThumbnail, true);
// Convert it to a CBitmap
CBitmap* pMonitorThumbnailBitmap = CBitmap::FromHandle(monitorThumbnail);
// Add the CBitmap to the CImageList
m_ImageListThumb.Add(pMonitorThumbnailBitmap, nullptr);
// Build the caption description
CString strMonitorDesc = m_monitors.strMonitorNames.at(monitorIndex);
strMonitorDesc.AppendFormat(L" (Screen %d)", monitorIndex + 1);
// Add the item to the CListCtrl
m_ListThumbnail.InsertItem(monitorIndex, strMonitorDesc, monitorIndex);
monitorIndex++;
}
// Start redrawiung the CListCtrl again
m_ListThumbnail.SetRedraw(TRUE);
}
If I change my code to pass false for the last parameter, so that it uses the original captured images without scaling down:
The colours are god there, so it is when I do:
if (bSmall)
{
CRect rt(0, 0, nWidth, nHeight);
//::FillRect(rImage.GetDC(), rt, static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)));
bRet = ::StretchBlt(rImage.GetDC(), 0, 0,
nWidth,
nHeight,
dcScreen.m_hDC,
rcCapture.left,
rcCapture.top,
rcCapture.Width(),
rcCapture.Height(), SRCCOPY | CAPTUREBLT);
}
that it messes up.
My issue was did not have anything to do with OnDrawItem. I simply included that to indicate how the image on the right was being rendered. I thought it may helped as background information. But it has probably confused the question and I may take it out in the long run!
Based on the comments I was reminded about SetStretchBltMode which was missing from CreateMonitorThumbnail. So, I now have this function:
BOOL CCenterCursorOnScreenDlg::CreateMonitorThumbnail(const int iMonitorIndex, CImage &rImage, bool bResizeAsThumbnail)
{
const CRect rcCapture = m_monitors.rcMonitors.at(iMonitorIndex);
// Destroy the currently contained bitmap to create a new one
rImage.Destroy();
// Massage the dimensions as we want a thumbnail
auto nWidth = rcCapture.Width();
auto nHeight = rcCapture.Height();
if (bResizeAsThumbnail)
{
nWidth = m_iThumbnailWidth;
auto dRatio = rcCapture.Width() / nWidth;
//nHeight = m_iThumbnailHeight;
nHeight = static_cast<int>(rcCapture.Height() / dRatio);
if (nHeight > m_iThumbnailHeight)
{
AfxMessageBox(L"Need to investigate!");
}
}
// Create bitmap and attach it to this object
if (!rImage.Create(nWidth, nHeight, 32, 0))
{
AfxMessageBox(L"Cannot create image!", MB_ICONERROR);
return FALSE;
}
// Create virtual screen DC
CDC dcScreen;
dcScreen.CreateDC(L"DISPLAY", nullptr, nullptr, nullptr);
// Copy (or resize) the contents from the virtual screen DC
BOOL bRet = FALSE;
auto dcImage = rImage.GetDC();
if (bResizeAsThumbnail)
{
// Set the mode first!
SetStretchBltMode(dcImage, COLORONCOLOR);
CPen penBlack;
penBlack.CreatePen(PS_SOLID, 3, RGB(0, 0, 0));
::Rectangle(dcImage, 0, 0, m_iThumbnailWidth, m_iThumbnailHeight);
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);
}
else
{
// Copy
bRet = ::BitBlt(dcImage, 0, 0,
rcCapture.Width(),
rcCapture.Height(),
dcScreen.m_hDC,
rcCapture.left,
rcCapture.top, SRCCOPY | CAPTUREBLT);
}
// Do cleanup and return
dcScreen.DeleteDC();
rImage.ReleaseDC();
return bRet;
}
That was the key to getting the thumbnail showing with the right colours:
I need to print some text (using font specified), than print a bitmap, using MFC. I can draw text on bitmap, than print this bitmap, using code below - but I need to print text, and than print bitmap in the bottom. The bitmap must be loaded from file.
CFont j1;
j1.CreateFont(
120, // nHeight
120, // nWidth
0, // nEscapement
0, // nOrientation
FW_NORMAL, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
RUSSIAN_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
"Arial"); // lpszFacename // lpszFacename
int w = 600, h = 400;
CClientDC dc(this);
CBitmap bmp;
CDC memdc;
memdc.CreateCompatibleDC(&dc);
bmp.CreateCompatibleBitmap(&dc, w, h);
if (!bmp.Attach(::LoadImage(
::GetModuleHandle(NULL), "D:\\UPM\\BMP\\Login.bmp", IMAGE_BITMAP, 0, 0,
LR_LOADFROMFILE | LR_CREATEDIBSECTION | LR_DEFAULTSIZE))) {
AfxMessageBox(_T("Error loading bitmap!")); return;
}
BITMAP bm;
bmp.GetBitmap(&bm);
auto oldbmp = memdc.SelectObject(bmp);
CFont* pOldFont = memdc.SelectObject(&j1);
//draw on bitmap
///memdc.FillSolidRect(0, 0, w, h, RGB(200, 200, 200));
memdc.SetTextColor(RGB(255, 0, 0));
CRect rc(0, 0, w, h);
memdc.DrawText("qwerty\nrtrtrt\nttttt", &rc, DT_WORDBREAK | DT_EXPANDTABS | DT_CENTER);
///pDC->DrawText(dpu, strRect, DT_WORDBREAK | DT_EXPANDTABS | DT_CENTER);
//dc.BitBlt(0, 0, w, h, &memdc, 0, 0, SRCCOPY);//optional: draw the bitmap on dialog
CPrintDialog pd(false);
if (pd.DoModal() == IDOK)
{
CDC PrintDC;
HDC hdc = pd.GetPrinterDC();
PrintDC.Attach(hdc);
DOCINFO docinfo = { sizeof(docinfo) };
docinfo.lpszDocName = "Print test";
PrintDC.StartDoc(&docinfo);
PrintDC.StartPage();
PrintDC.BitBlt(0, 0, w, h, &memdc, 0, 0, SRCCOPY);
PrintDC.EndPage();
PrintDC.EndDoc();
}
dc.SelectObject(oldbmp);
CClientDC dc(this);
dc.DrawText(...);
...
PrintDC.BitBlt(0, 0, w, h, &memdc, 0, 0, SRCCOPY);
You are drawing text on display's "client DC", then drawing a bitmap on a "printer DC".
Use instead a paint function for everything, and a paint_bitmap function to make things easier.
void paint_bitmap(CDC& dc, CBitmap &bmp, CRect rc)
{
CDC memdc;
memdc.CreateCompatibleDC(&dc);
auto oldbmp = memdc.SelectObject(&bmp);
dc.BitBlt(rc.left, rc.top, rc.Width(), rc.Height(), &memdc, 0, 0, SRCCOPY);
memdc.SelectObject(oldbmp);
}
void paint(CDC& dc)
{
CBitmap bmp;
if (!bmp.Attach(...))...
dc.DrawText(L"text", &rc, ...);
rc.OffsetRect(0, 200);
paint_bitmap(dc, bmp, rc);
}
...
CPrintDialog pd(false);
if (pd.DoModal() == IDOK)
{
HDC hdc = pd.GetPrinterDC();
if (hdc)
{
...
dc.StartPage();
paint(dc); //<- use this for printer or display
dc.EndPage();
}
To print directly to default printer:
CPrintDialog pd(false);
if (pd.GetDefaults() && pd.m_pd.hDC)
{
CDC dc;
dc.Attach(pd.m_pd.hDC);
DOCINFO docinfo = { sizeof(docinfo) };
docinfo.lpszDocName = L"Print test";
dc.StartDoc(&docinfo);
dc.StartPage();
paint(dc);
dc.EndPage();
dc.EndDoc();
}
else
{
MessageBox(L"no default printer...");
}
or if you want a particular printer which you are sure is there, use
HDC hdc = CreateDC(L"WINSPOOL", L"Microsoft Print to PDF", NULL, NULL);
if (hdc)
{
CDC dc;
dc.Attach(hdc);
...
//DeleteDC(hdc); CDC will take care of delete
}
I want to print a bitmap. To avoid printing small bitmap I set CScrollView mode as MM_LOMETRIC with sizes 3830 x 1995. I have created the bitmap and made the bitblt to the screen. There were everythig just like I want on the screen and on the print preview but when I printed the document I've got very bad result.
The same picture on print preview.
It seems to me that printer does not see a bitmap the same way as print preview does.
Pay attantion that the first ractangle puts directly on the DC and memDC puts into it.
Are there any ideas how to fix this mismatch between print previw and the real printing?
Project files
void OnDraw()
{
CPen pen;
pen.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
CPen* OldPen = pDC->SelectObject(&pen);
CRect rcView;
GetClientRect(rcView);
int iClientWidth = rcView.right;
int iClientHeight = rcView.bottom;
int iMemWidth = 1900;
int iMemHeight = 950;
CDC memDC;
CBitmap memBitmap;
memDC.CreateCompatibleDC(pDC);
memBitmap.CreateCompatibleBitmap(pDC, iMemWidth, iMemHeight);
memDC.SelectObject(&memBitmap);
memDC.SetMapMode(MM_LOMETRIC);
CPen pen1;
pen1.CreatePen(PS_SOLID, 3, RGB(0, 0, 0));
memDC.SelectObject(&pen1);
CBrush brBK;
brBK.CreateSolidBrush(RGB(255, 255, 255));
memDC.SelectObject(&brBK);
RECT rc;
rc.left = 0;
rc.top = 0;
rc.right = iMemWidth;
rc.bottom = iMemHeight;
memDC.FillRect(&rc, &brBK);
memDC.Rectangle(rc.left, rc.top, rc.right, -rc.bottom);
memDC.MoveTo(0, 0);
memDC.LineTo(1900, -950);
memDC.MoveTo(0, -950);
memDC.LineTo(200, -750);
CFont font;
font.CreateFont(
50, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_NORMAL, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
ANSI_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
_T("Arial"));
memDC.SelectObject(&font);
memDC.TextOut(100, -100, _T("Hello"));
pDC->BitBlt(10, -10, iMemWidth, -iMemHeight, &memDC, 0, 0, SRCCOPY);
font.DeleteObject();
brBK.DeleteObject();
memDC.DeleteDC();
memBitmap.DeleteObject();
pen.DeleteObject();
pen1.DeleteObject();
}
void OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
CSize sizeTotal;
sizeTotal.cx = 3830;
sizeTotal.cy = 1995;
SetScrollSizes(MM_LOMETRIC, sizeTotal);
}
I'd like to create a frame window that can contain child windows, without using MDI which is way too complex for my needs.
So, I create a frame window CMainFrame derived from CFrameWnd and then a class Child derived from CWnd, with the following constructor:
Child::Child()
{
CString strWndClass = AfxRegisterWndClass(CS_VREDRAW | CS_HREDRAW, 0, 0, 0);
CWnd *cwnd = AfxGetApp()->m_pMainWnd;
Create(strWndClass, "Title child", WS_CHILD, CRect(0, 0, 200, 200), cwnd, 0, NULL);
}
But when I create the Child window from the main frame:
void CMainFrame::Click()
{
Child *child = new Child();
child->ShowWindow(SW_SHOW);
}
nothing appears. Though, the creation of the child did not fail. What's the problem?
I would like to draw a string on the screen, rotated by 90 degrees, on a transparent background:
public static void drawStringWithTransformROT90(String text, int x, int y, int color, Graphics g) {
// create a mutable image with white background color
Image im = Image.createImage(g.getFont().stringWidth(text), g.getFont().getHeight());
Graphics imGraphics = im.getGraphics();
// set text color to black
imGraphics.setColor(0x00000000);
imGraphics.drawString(text, 0, 0, Graphics.TOP|Graphics.LEFT);
int[] rgbData = new int[im.getWidth() * im.getHeight()];
im.getRGB(rgbData, 0, im.getWidth(), 0, 0, im.getWidth(), im.getHeight());
for (int i = 0; i < rgbData.length; i++) {
// if it is the background color (white), set it to transparent
if (rgbData[i] == 0xffffffff) {
rgbData[i] = 0x00000000;
} else {
// otherwise (black), change the text color
rgbData[i] = color;
}
}
Image imageWithAlpha = Image.createRGBImage(rgbData, im.getWidth(), im.getHeight(), true);
Sprite s = new Sprite(imageWithAlpha);
// rotate the text
s.setTransform(Sprite.TRANS_ROT90);
s.setPosition(x, y);
s.paint(g);
}
Is there any better way to do this? Should I create a transparent image with the alphabet rotated, and draw it using a Sprite object?
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.Sprite;
public class MyCanvas extends Canvas {
public void paint(Graphics g) {
//The text that will be displayed
String s="java";
//Create the blank image, specifying its size
Image img=Image.createImage(50,50);
//Create an instance of the image's Graphics class and draw the string to it
Graphics gr=img.getGraphics();
gr.drawString(s, 0, 0, Graphics.TOP|Graphics.LEFT);
//Display the image, specifying the rotation value. For example, 90 degrees
g.drawRegion(img, 0, 0, 50, 50, Sprite.TRANS_ROT90, 0, 0, Graphics.TOP|Graphics.LEFT);
}
}
As found at http://wiki.forum.nokia.com/index.php/How_to_display_rotated_text_in_Java_ME
If you use Java2D for drawing you can specify java.awt.Graphics2D#setTransform.