我想在屏幕外渲染一个控件到一些位图,以便我可以快速访问它.
不幸的是,Control.DrawToBitmap
似乎绘制了它所调用的整个控件,包括它的所有子控件.在内部,它向位图发出带有自提供DC的WM_PRINT消息.然后将此临时位图blitting到用户提供的位图.对我来说不可接受,我宁愿根据需要更新这个位图,以便在需要位图时最小化我的性能.
在理想情况下,我希望表单的行为就像它在屏幕上可见(但它不可能).这意味着,如果某个控件的Text
属性发生了变化,则表单将部分失效.然后,捕获相关的消息/事件将允许我为要绘制的表单指定我自己的DC,或者简单地将表单DC BitBlt到我自己的DC.
我看过的一些方向:
PaintEventArgs
参数OnPaint
似乎举行成员savedGraphicsState,也许它可以用来找出不需要无效我正试图挂钩第三方应用程序,以便我可以绘制到它的屏幕.在屏幕上绘图是容易的,我需要它没有帮助,但我似乎有使用问题SetWindowsHookEx
来处理WH_GETMESSAGE
.我无法弄清楚最后两个参数传递的内容.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowDrawer
{
public partial class Form1 : Form
{
private delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
static IntPtr hHook;
IntPtr windowHandle;
uint processHandle;
HookProc PaintHookProcedure;
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern System.IntPtr FindWindowByCaption(int ZeroOnly, string lpWindowName);
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SetWindowsHookEx", SetLastError = true)]
static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint …
Run Code Online (Sandbox Code Playgroud) 可以使用GetDC/ReleaseDC在窗口的客户区域中绘制.但是响应WM_PAINT消息,必须使用BeginPaint/EndPaint.这有什么特别之处吗?
我正在尝试使用Windows API在具有透明背景的窗口上绘制动画.问题是我无法从窗口中删除以前的图形.
我设置了以下参数:
InvalidateRect(m_hWnd, &sClientRect, TRUE); // we set the bErase parameter as TRUE
paintParams.dwFlags = BPPF_ERASE; // erase window content while copying backbuffer
paintParams.pBlendFunction = &m_sBlendfunc; // copy source image to backbuffer
Run Code Online (Sandbox Code Playgroud)
但它仍然无效.您可以在附加图像中看到结果.我想要的动画是在屏幕上移动圆圈.我得到的(如附图所示)是他们运动的人工制品,因为在每次抽奖之前窗口没有被清除.
请参阅下面的完整代码:
#include "DrawTest.h"
DrawTest* m_sDrawTest;
DrawTest::DrawTest()
{
m_pAnimation = NULL;
m_sDrawTest = NULL;
m_nFrameindex = 0;
}
DrawTest::~DrawTest(void)
{
if(m_pAnimation)
delete m_pAnimation;
m_pAnimation = NULL;
if(m_sDrawTest)
delete m_sDrawTest;
m_sDrawTest = NULL;
}
int DrawTest::Init(AnimationManager* pAnimationManager,HINSTANCE hInstance,int nCmdShow)
{
//listener
m_sDrawTest = this;
//get anemation (sequence of …
Run Code Online (Sandbox Code Playgroud) 我需要一些调试Delphi XE2应用程序崩溃的建议.我自己从来没有见过崩溃 - 事实上它很少发生,并且不能按要求重现.
我们确实从MadExcept获得了一组10个崩溃报告.这些表明主线程在主窗体的列表视图中处理WM_PAINT消息.每种情况下的调用堆栈都没有显示对我自己的代码的引用,只显示了comctl32.dll,ntdll.dll和USER32.dll中的VCL代码和函数.
有问题的列表视图是TColorListView,它派生自TCustomListView,并处理OnCustomDrawItem和OnDeletion事件.但正如我所说,当崩溃发生时,我的TColorListView代码都没有在调用堆栈上.
每种情况下崩溃的实际位置都有所不同,但是通向它的调用顺序(从早到晚)始终是:
KiUserCallbackDispatcher
RtlAnsiStringToUnicodeString
StdWndProc
TWinControl.MainWndProc
TCustomListView.WndProc
TWinControl.WndProc
TControl.WndProc
TCustomListView.WMPaint
TWinControl.WMPaint
TWinControl.WMPaint
TWinControl.DefaultHandler
CallWindowProcA
TControl.WndProc
Run Code Online (Sandbox Code Playgroud)
之后它进入StdWndProc/SendMessageW/TControl.Perform之一,每次路径都不同.最终它最终出现在comctl32.dll,USER32.dll,GDI32.dll或者只是TControl.WndProc中,并引发了EAccessViolation.遗憾的是,我没有关于用户当时尝试做什么的信息,因为用户没有填写错误报告的那一部分.
您能否建议我使用任何"通灵调试"技术来确定崩溃的原因(从而修复它)?
更新以回答以下评论中的问题:
procedure TColorListView.HandleCustomDrawItem(aSender: TCustomListView; aItem: TListItem;
aState: TCustomDrawState; var aDefaultDraw: Boolean);
begin
Canvas.Font.Color := ItemColors[aItem.Index];
end;
Run Code Online (Sandbox Code Playgroud)
在(仅)其中一个崩溃报告中,它似乎进入TListItem.GetIndex并进一步崩溃了几个堆栈帧.这可能是一个红鲱鱼.
什么是'Perform'ed消息?对不起,我不知道.MadExcept没有给我方法参数值; 只是方法名称.
5月31日
虽然我更愿意根据我的信息找到错误,但我也欢迎我可以添加到程序中的任何新诊断的建议,以便如果在下一个版本之后再次发生这种崩溃,我将会继续.我很茫然,因为在崩溃时我甚至没有修改的代码甚至在调用堆栈上.
6月13日
我在MadExcept报告中添加了一行,告诉我发生异常时应用程序处于什么状态 - Starting/Active/Idle/ModalDlg/Terminated.(感谢Chris Thornton提出的建议.)我认为在关机期间发生异常的可能性是合理的.不幸的是,直到2014年我们才发布新版本并且有可能通过新诊断获取错误报告.
是否有一个函数可以冻结窗口重新绘制一段时间,同时我对对话框的布局进行了更改?
MSDN和众多帖子都建议在WM_PAINT中使用BeginPaint/EndPaint.我也看到很多地方建议如果在绘画中使用双缓冲,在WM_CREATE初始化DC和mem分配并在WM_PAINT中重用这些句柄更有意义.
例如,使用BeginPaint,我经常看到:
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
MemDC = CreateCompatibleDC(hdc);
bmp = CreateCompatibleBitmap(hdc, width, height);
oldbmp = SelectObject(MemDC,bmp);
g = new Graphics(MemDC);
//do paint on bmp
//blt bmp back to hdc
EndPaint(hWnd, &ps);
DeleteObject(bmp);
g->ReleaseHDC(MemDC);
DeleteDC(MemDC);
delete g;
Run Code Online (Sandbox Code Playgroud)
要保存初始化和拆除,是否可以执行此操作:
case WM_CREATE:
hdc = GetDC(hWnd);
//create memDC and graphics object references ...
case WM_DESTROY
//delete memDC and graphics object references...
case WM_PAINT
BeginPaint(hWnd, &ps);
//use previously create mem and graphics object to paint
EndPaint(hWnd, &ps);
Run Code Online (Sandbox Code Playgroud)
因此,我们仅使用EndPaint清除更新区域,但将图形委托给prev创建的对象.
我正在处理很多绘图.目前我正在使用WM_TIMER来使用InvalidateRect计划绘画.由于某种原因,WM_PAINT经常被调用区域(0,0,0,0),所以基本上是一个空矩形.我试图将其解释为"整个窗口",但之后它似乎会导致性能下降.为什么Windows发送呢?
有人可以解释为什么使用DefWindowProc一切正常,但如果我删除它,字符串"Hello windows"出现在屏幕上没有窗口和任何按钮?"UpdateWindow"发送到窗口过程WM_PAINT消息,那么为什么显示文本但是跳过了窗口的创建?
#include <windows.h>
LRESULT CALLBACK proc1 (HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("Program");
HWND hwnd1;
MSG msg1;
WNDCLASS wndclass1;
wndclass1.style = CS_HREDRAW | CS_VREDRAW;
wndclass1.lpfnWndProc = proc1;
wndclass1.cbClsExtra = 0;
wndclass1.cbWndExtra = 0;
wndclass1.hInstance = hInstance;
wndclass1.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndclass1.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclass1.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wndclass1.lpszMenuName = NULL;
wndclass1.lpszClassName = szAppName;
RegisterClass (&wndclass1);
hwnd1 = CreateWindow ( szAppName, …
Run Code Online (Sandbox Code Playgroud) 我已经读过,我不应该WM_PAINT
手动发送,InvalidateRect
而是应该打电话但是没有找到任何关于为什么不发送的信息.那为什么不呢?
更新适用InvalidateRect
但不适用SendMessage(WM_PAINT)
LRESULT CALLBACK window_proc(HWND wnd, UINT msg, WPARAM w_param, LPARAM l_param)
{
switch (msg)
{
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(wnd, &ps);
Polyline(..);
EndPaint(wnd, &ps);
return 0;
case WM_USER:
// SendMessage(wnd, WM_PAINT, NULL, NULL);
// InvalidateRect(wnd, NULL, FALSE);
return 0;
}
}
Run Code Online (Sandbox Code Playgroud) wm-paint ×10
winapi ×7
c++ ×4
windows ×3
c# ×2
gdi ×2
gdi+ ×2
debugging ×1
delphi ×1
delphi-xe2 ×1
invalidation ×1
off-screen ×1
paint ×1
transparency ×1