[Closed] Can DotNet screen cap part of the screen?
Is it possible with DotNet to “screencap” a portion of the screen? I have a dialog that flashes and flickers alot as it redraws itself, and I’d like to take a screencap of the dialog before the redrawing, and use that bitmap to cover up the dialog while it redraws, and then remove the bitmap once the redrawing is done, so it appears to be an instantanous update.
Is it possible with DotNet to capture a portion of the screen?
Thanks!
Well I’m guessing worst case scenario, you could just capture the whole screen and crop the part you want, but it’s not a very clean solution. Is the dialog/control that flashes also .NET? Most of those have some methods to disable redraws while you update them.
I’m totally fine with first grabbing the entire screen, and then cropping down if necessary (although I highly suspect there would be a way to feed the dotnet function a rect so it can target just the area I need)
The dialog is not a DotNet form, it’s a maxscript rollout opened as a dialog, containing a mixture of native maxscript controls and DotNet controls.
Thanks.
Yhea probably, I was just suggestion a possible course of action if you couldn’t make that work.
However I still think you should check all other possibilities first. What about setting the visible property to false on all controls?
I haven’t tried that yet, but I’m pretty sure I’ll still see some flashing… all the controls will disapear for a frame, and then reappear in their new configurations. It’s that flashing that I’m trying to eliminate.
the best way to reduce flickering is to disable redraw of whole window before updating of the controls and set to enable after. it’s easy to do. (and much faster then make a screenshot)
Denis,
I’m only aware of disableSceneRedraw() for disabling the redrawing of scenes, and that only seems to affect the 3D world itslef, and not the various UI’s. Is there another command that disables the UI’s from being redrawn as well?
Thanks.
it’s how to lock/unlock window redraw:
fn getWinRedrawClass =
(
source = ""
source += "using System;
"
source += "using System.Runtime.InteropServices;
"
source += "class WinRedraw
"
source += "{
"
source += " [DllImport(\"user32.dll\")]
"
source += " static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate, IntPtr hrgnUpdate, uint flags);
"
source += " public bool RedrawAllWindow(IntPtr hWnd, uint flags) { return RedrawWindow(hWnd, IntPtr.Zero, IntPtr.Zero, flags); }
"
source += " public bool RedrawAllWindow(Int32 hWnd, uint flags) { return RedrawWindow((IntPtr)hWnd, IntPtr.Zero, IntPtr.Zero, flags); }
"
source += "}
"
csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
compilerParams.ReferencedAssemblies.Add("System.dll");
compilerParams.GenerateInMemory = on
compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
input = compilerResults.CompiledAssembly.CreateInstance "WinRedraw"
)
global WinRedrawClass = if WinRedrawClass == undefined then getWinRedrawClass() else WinRedrawClass
try(destroydialog RedrawTestRol) catch()
rollout RedrawTestRol "Redraw Test" width:200 height:240
(
fn setWindowRedraw hwnd act = if hwnd != undefined do
(
local WM_SETREDRAW = 0x000B
windows.sendmessage hwnd WM_SETREDRAW act 1
)
dotNetControl tv "TreeView" backcolor:(dotNetClass "System.Drawing.Color").Gray width:200 height:200 pos:[0,0]
button b1 "" width:22 pos:[-100,0]
button b2 "" width:22 pos:[-100,0]
button b3 "" width:22 pos:[-100,0]
button b4 "" width:22 pos:[-100,0]
button b5 "" width:22 pos:[-100,0]
button lockRedraw "Lock Redraw" width:90 pos:[8, 210]
button withRedraw "With Redraw" width:90 pos:[100, 210]
local buttons = #()
local hwnd
fn loadTV =
(
i = dotnetobject "TreeNode" ""
items = for k=1 to 400 collect
(
item = i.clone()
item.text = "Item " + k as string
item
)
tv.BeginUpdate()
tv.nodes.clear()
tv.nodes.addrange items
tv.EndUpdate()
tv.Refresh()
)
on lockRedraw pressed do
(
setWindowRedraw hwnd 0 -- set redraw to off
for b in buttons do b.pos = random [0,0] [158,178]
loadTV()
setWindowRedraw hwnd 1 -- set redraw to on
flags = 0x81 -- RDW_INVALIDATE | RDW_ALLCHILDREN
-- or
flags = 0x01 -- RDW_INVALIDATE
WinRedrawClass.redrawallwindow hwnd flags -- force redraw
)
on withRedraw pressed do
(
for b in buttons do b.pos = random [0,0] [158,178]
loadTV()
)
on RedrawTestRol open do
(
loadTV()
hwnd = (windows.getChildHWND 0 "Redraw Test")[1]
buttons = for b in RedrawTestRol.controls where iskindof b ButtonControl and b.text == "" collect
(
b.pos = random [0,0] [158,178]
b.text = b.name
b
)
)
)
createdialog RedrawTestRol
if anyone knows how to force window redraw without c#, please let me know
What exactly are you drawing into? Dotnet objects or Max rollouts and UI items? What you are suggesting would be very slow.
Paul,
Well, right now, when the user hits a certain button causing the dialog to reconfigure itself, I have a big button appear over the entire dialog area to cover up the controls moving to new positions. Once they’re all in place, I move the big button off to -1000,-1000 to reveal the dialog controls again. This of course causes the entire dialog interface to appear blanked out for one frame, but at least keeps the user from seeing individual controls scaling/moving to new locations.
So my thought was, that if I could apply a bitmap to the large button that blocks everything, and that bitmap is just a screenshot of what the dialog looked like before the reconfiguration, it would completely removing the perception of any flashing or anything.
Interesting idea. Not sure how to go about that. Does this take a long time?
If you place the controls inside a Panel control, you can use the DrawToBitmap method. You could also have a look at the invalidate and update methods.
Edit: Better yet, try SuspendLayout and ResumeLayout