Moving panel with directshow video renderer in it - c#

I have a few panels with different directshow IVideoWindow handles bound to them so that the videos get shown inside the panels (WindowStyle properties are: Child,ClipSiblings,ClipChildren,Caption) Now I would like to move these panels around but I can only manage to move them when the video content is not filling the entire panel and I'm clicking+holding mouse button on the empty panel space. I can move the video windows around in the panels but of course they only move inside their respective panel space.
Is there a way to bind the video window content directly to the panel , for example the entire panel with content moves freely around when I click+hold the videowindow menu bar?
Thanks in advance.
Forgot to mention,this is in c#.

I use the Video Mixing Renderer 9 and have it tied to a user control. I have set the VMR9 to Windowless mode and then set the video clipping window on the IVMRWindowlessControl9 interface to the handle of my user control. I also set the video to fill the panel completely, using IVMRWindowlessControl9.GetNativeVideoSize, IVMRWindowlessControl9.SetAspectRatioMode, and IVMRWindowlessControl9.SetVideoPosition whenever the panel gets resized. When the form that contains my user control gets moved around, the video follows along. This is all done with C# and DirectShow.NET.
Edited to add sample code:
public partial class VideoPanel : UserControl
{
private VideoMixingRenderer9 _renderer;
private IVMRWindowlessControl9 _windowlessControl;
public VideoMixingRenderer9 Renderer
{
get
{
return _renderer;
}
set
{
_renderer = value;
if (_renderer != null)
{
var filterConfig = _renderer as IVMRFilterConfig9;
if (filterConfig != null)
{
filterConfig.SetRenderingMode(VMR9Mode.Windowless);
_windowlessControl = _renderer as IVMRWindowlessControl9;
if (_windowlessControl != null)
{
_windowlessControl.SetVideoClippingWindow(Handle);
SetSize();
}
}
}
}
}
private void SetSize()
{
var srcRect = new DsRect();
var dstRect = new DsRect(ClientRectangle);
int arWidth, arHeight;
_windowlessControl.GetNativeVideoSize(out srcRect.right, out srcRect.bottom, out arWidth, out arHeight);
_windowlessControl.SetAspectRatioMode(VMR9AspectRatioMode.LetterBox);
_windowlessControl.SetVideoPosition(srcRect, dstRect);
}
}

I solved it finally and I can't believe how silly I was. I left out the
hr = videoWindow.put_MessageDrain(hWin.Handle);
line , of course the videowindow wouldnt "listen" to the panel.

Related

Printing a scroll-able windows form. [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I take a screenshot of a Winforms control/form in C#?
I have a windows form with a list of names and pictures. The list is long and so there is a scroll panel for it. Now, I would like to print this form but I can't because the the print function only prints the "visible" portion since the invisible portion is seen when you scroll down. So, is there a way to print the whole form at once?
Look for the Print form control in the Visual Basic PowerPacks toolbox
To print the complete client area of a scrollable form try this...
1.In the Toolbox, click the Visual Basic PowerPacks tab and then drag the PrintForm component onto the form.
The PrintForm component will be added to the component tray.
2.In the Properties window, set the PrintAction property to PrintToPrinter.
3.Add the following code in the appropriate event handler (for example, in the Click event handler for a Print Button).
1.PrintForm1.Print(Me, PowerPacks.Printing.PrintForm.PrintOption.Scrollable)
Give this a shot and let me know how it works out for you.
This is not exactly a complete answer, but here is a piece of code that takes a screenshot (a bitmap) of a scrollable Panel control on a Form. The big drawback is the screen flickers while the screenshot is taken. I have tested it on simple apps, so it may not work in all cases, but that could be a start.
Here is how to use it:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent(); // create a scrollable panel1 component
}
private void button1_Click(object sender, EventArgs e)
{
TakeScreenshot(panel1, "C:\\mypanel.bmp");
}
}
And here is the utility:
public static void TakeScreenshot(Panel panel, string filePath)
{
if (panel == null)
throw new ArgumentNullException("panel");
if (filePath == null)
throw new ArgumentNullException("filePath");
// get parent form (may not be a direct parent)
Form form = panel.FindForm();
if (form == null)
throw new ArgumentException(null, "panel");
// remember form position
int w = form.Width;
int h = form.Height;
int l = form.Left;
int t = form.Top;
// get panel virtual size
Rectangle display = panel.DisplayRectangle;
// get panel position relative to parent form
Point panelLocation = panel.PointToScreen(panel.Location);
Size panelPosition = new Size(panelLocation.X - form.Location.X, panelLocation.Y - form.Location.Y);
// resize form and move it outside the screen
int neededWidth = panelPosition.Width + display.Width;
int neededHeight = panelPosition.Height + display.Height;
form.SetBounds(0, -neededHeight, neededWidth, neededHeight, BoundsSpecified.All);
// resize panel (useless if panel has a dock)
int pw = panel.Width;
int ph = panel.Height;
panel.SetBounds(0, 0, display.Width, display.Height, BoundsSpecified.Size);
// render the panel on a bitmap
try
{
Bitmap bmp = new Bitmap(display.Width, display.Height);
panel.DrawToBitmap(bmp, display);
bmp.Save(filePath);
}
finally
{
// restore
panel.SetBounds(0, 0, pw, ph, BoundsSpecified.Size);
form.SetBounds(l, t, w, h, BoundsSpecified.All);
}
}

Clickable image grid in windows form?

If this is a dumb question, forgive me. I have a small amount of experience with C#, but not to this degree yet.
I have a series of images that I want to put into a grid with space around each image, also text beneath them and I want them to be clickable, so when they're clicked they hilite, and double click runs an event. The best example I have for this is the user interface of the program ACDSee. I've googled this for hours, and haven't come up with anything applicable. Is this difficult or simple? Can anyone give me an example, or point me in the right direction?
Cheers.
It doesn't seem to be very difficult. I would suggest the following steps:
Add a new "User Control" to your project for image thumbnails. It can contain a docked PictureBox and a Label or LinkLabel at its bottom.
For the space around each thumbnail simply play with the Padding property of the user control.
For the so called grid that is going to hold the thumbnails, use a FlowLayoutPanel, and simply add instances of the above mentioned user-control to this panel.
For visual representation of being selected, change the background color of the user-control instance to blue (for example), and back to control-face when deselected. It is recommended to implement an IsSelected property for the user-control as well.
To emulate thumbnail selection, handle the Click event of the user-control and assign the events for all thumbnail instances to a single event-handler method. Store a global reference to the already selected thumbnail, name it e.g., SelectedThumbnail initialized with null. In the event-handler body compare the sender with the global SelectedThumbnail, and update it if required. If the user-control associated with the sender is not selected (i.e., its background is not blue, or IsSelected is false) make it selected, or change its background. Otherwise change the background to its default color (e.g., control-face).
The Click event handler body looks something like this:
MyThumbnailControl ctrl = sender as MyThumbnailControl;
if(ctrl == null) return;
if(ctrl == SelectedThumbnail) return; // selected again
if(ctrl != SelectedThumbnail)
{
ctrl.IsSelected = true;
ctrl.BackColor = Color.Blue;
// it's better to set the back-color in the IsSelected property setter, not here
SelectedThumbnail.IsSelected = false;
SelectedThumbnail.BackColor = Color.Control;
SelectedThumbnail = ctrl; // important part
}
It's also recommended that all thumbnail instances that are going to be added to the so-called grid, be referenced in a separate array too. Therefore changing selection with arrow-keys would be possible with simple index calculations.
Further Notes: I assumed that the user-control that is to be created is named MyThumbnailControl, just a random name to refer to that control. When you create a new user-control, the wizard generates a class for you with your desired name (e.g., MyThumbnailControl), you can define a property inside it named IsSelected and implement its getter and setter. See this for a tutorial. After defining the user-control you can instantiate instances from its corresponding class. Also by global reference, I meant a variable at the form (or any parent control) level. To keep it simple we can add a reference of the selected thumbnail in the form that is going to hold the grid and thumbnails: MyThumbnailControl selectedThumb = null; or something like this in the body of the form.
Here is something, I just fixed you.
Create a C# project name CreateImageList and in the Form1 add the following 5 controls with their default name i.e. Panel1, PictureBox1, Label1, Button1, Button2:
How it works:
When the page load it create an imageList objects and load all .jpg images from a folder you provide
ImageList Images are set into the PictureBox control and when user clicks "Button1" the picturebox shows next image in ImageList and when user clicks "Button2" the PictureBox shows previous image from ImageList.
The Label1 shows the currentImage counter from the ImageList Arrage. If you want to write something specific, you can create an array of text and sync with your image counter.
When user click on PictureBox the a border is create to show Picture highlighted
When user Double Click on PictureBox a MessageBox appears shows DoubleClick event.
Now, you can use the following code:
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;
using System.IO;
namespace CreateImageList
{
public partial class Form1 : Form
{
private int currentImage = 0;
protected Graphics myGraphics;
ImageList iPicList = new ImageList();
public Form1()
{
InitializeComponent();
DirectoryInfo dirImages = new DirectoryInfo("C:\\2012");
iPicList.ImageSize = new Size(255, 255);
iPicList.TransparentColor = Color.White;
myGraphics = Graphics.FromHwnd(panel1.Handle);
foreach (FileInfo file in dirImages.GetFiles())
{
if (file.Extension == ".jpg")
{
Image myImage = Image.FromFile(file.FullName);
iPicList.Images.Add(myImage);
}
}
if (iPicList.Images.Empty != true)
{
panel1.Refresh();
currentImage = 0;
// Draw the image in the panel.
iPicList.Draw(myGraphics, 1, 1, currentImage);
// Show the image in the PictureBox.
pictureBox1.Image = iPicList.Images[currentImage];
label1.Text = "Image #" + currentImage;
}
}
private void showImage(int imgIndex)
{
// Draw the image in the panel.
iPicList.Draw(myGraphics, 1, 1, currentImage);
// Show the image in the PictureBox.
pictureBox1.Image = iPicList.Images[currentImage];
label1.Text = "image #" + currentImage;
panel1.Refresh();
}
private void button1_Click(object sender, EventArgs e)
{
if (iPicList.Images.Count - 1 > currentImage)
{
currentImage++;
}
else
{
currentImage = 0;
}
showImage(currentImage);
}
private void button2_Click(object sender, EventArgs e)
{
if (iPicList.Images.Count - 1 >= currentImage)
{
if (currentImage == 0)
currentImage = iPicList.Images.Count-1;
else
currentImage--;
}
else
{
currentImage = iPicList.Images.Count;
}
showImage(currentImage);
}
private void pictureBox1_DoubleClick(object sender, EventArgs e)
{
MessageBox.Show("Picture Box Double clicked");
}
private void pictureBox1_Click(object sender, EventArgs e)
{
panel1.Refresh();
myGraphics.DrawRectangle(Pens.Black, 0, 0, iPicList.Images[currentImage].Width + 1, iPicList.Images[currentImage].Height + 1);
pictureBox1.Image = iPicList.Images[currentImage];
}
}
}
The changes you need are:
Change the Following folder to a place where you have lots of jpg:
DirectoryInfo dirImages = new DirectoryInfo("C:\\2012");
Also if you are dealing with other kind of images, make change here:
if (file.Extension == ".jpg") // Change it to your image type.
If you don't want to use the the buttons to go up and down, you have several other options to host PictureBox control in scrollable Panel or list or something else.

Load image into picturebox only when needed/visible

I'm programming a little application that shows thumbnails of images. All the displayed images are in the same directory, each Image is inside it's own groupbox with a few labels and a checkbox. All the group boxes get added to a flowlayoutpanel. The problem is, that the amount of images may get pretty large and I'm concerned that memory usage / performance might get a little out of hand if I load all images even if they're not yet visible.
Is there a way to load only images that are currently visible to the user? My first thought is storing the location of my boxes and determine which images to load depending on the scroll position, or is there an easier way to determine if a picturebox/groupbox is currently visible?
Ideally what you should be doing is creating buffer logic rather than hiding 1 image and showing the other. It's a much better idea to have a couple buffers loading the images before you show them and have a fixed number of actual fields showing images rather than a new set per image.
But if your solution requires that, try to create a custom user control.
Try something like this:
public class customUserControl : UserControl
{
//Store image as a Uri rather than an Image
private Uri StoredImagePath;
public class PictureBoxAdv : PictureBox
{
public PictureBoxAdv()
{
this.VisibleChanged +=new EventHandler(VisibleChanged);
}
}
public Uri Image
{
get { return StoredImagePath; }
set
{
StoredImagePath = value;
if (this.Visible && StoredImagePath != null)
{
this.Image = Image.FromFile(StoredImagePath.AbsolutePath);
}
}
}
public void VisibleChanged(object sender, EventArgs e)
{
//When becomes visible, restore image, invisible, nullify.
if (this.Visible && StoredImagePath != null)
{
this.Image = Image.FromFile(StoredImagePath.AbsolutePath);
}
else
{
this.Image = null;
}
}
}

Enable a button to be clicked at design-time in Visual Studio?

My setting:
I've got a C# application (.NET 3.5) in Visual Studio 2008. No chance to switch to WPF or whatsoever :).
My app contains a custom control (a button class derived from Windows.Forms.Button) that acts as a replacement for the Windows.Forms.TabControl. I can associate these buttons with one another and each button can be associated with one control that it is dealing with (usually some sort of Windows.Forms.Panel). It looks something like this:
public class TabButton : System.Windows.Forms.Button
{
// ...
protected override void OnClick(EventArgs e)
{
base.OnClick(e);
this.myAssociatedControl.Visible = true;
this.tellMyBuddiesToHideTheirControls();
}
// ...
}
Basically it is just about clicking a button, showing its bound control and having the controls bound to the associated buttons disappear - just like the TabControl, but the approach is easily designable and I can place the buttons far from their content panels.
The problem:
This works pretty well at runtime, but the usage at design time is arguably odd: With the mouse, find a control that´s belonging to the group and run a series of <Send To Back>s until the desired control is visible.
The question:
Is there a way to tell the VS designer to evaluate the clicks on the buttons at design time like it does with the TabControl so that I can switch the tabs just by clicking them like I would at runtime?
I've been searching for quite a while now. There are some articles here at SO but they only seem to cover adding additional attributes to the properties designer.
Edith says:
By request, an answer to my own question ...
This is the solution that is suitable to my application. It is basically an example from the msdn with some twists to get the custom designer to use a callback on click. Hope it helps anyone :-).
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
public class TabButtonDesigner : System.Windows.Forms.Design.ControlDesigner
{
ShowTabGlyph myGlyph = null;
Adorner myAdorner;
public TabButtonDesigner()
{
}
public override void Initialize(IComponent component)
{
base.Initialize(component);
// Add the custom set of glyphs using the BehaviorService.
// Glyphs live on adornders.
myAdorner = new Adorner();
BehaviorService.Adorners.Add(myAdorner);
myGlyph = new ShowTabGlyph(BehaviorService, Control);
myGlyph.Callback = () =>
{
((MyCustomTabButton)this.Control).ShowMyTab();
};
myAdorner.Glyphs.Add(myGlyph);
}
class ShowTabGlyph : Glyph
{
Control control;
BehaviorService behaviorSvc;
public Action Callback
{
get;
set;
}
public ShowTabGlyph(BehaviorService behaviorSvc, Control control) :
base(new ShowTabBehavior())
{
this.behaviorSvc = behaviorSvc;
this.control = control;
}
public override Rectangle Bounds
{
get
{
// Create a glyph that is 10x10 and sitting
// in the middle of the control. Glyph coordinates
// are in adorner window coordinates, so we must map
// using the behavior service.
Point edge = behaviorSvc.ControlToAdornerWindow(control);
Size size = control.Size;
Point center = new Point(edge.X + (size.Width / 2),
edge.Y + (size.Height / 2));
Rectangle bounds = new Rectangle(
center.X - 5,
center.Y - 5,
10,
10);
return bounds;
}
}
public override Cursor GetHitTest(Point p)
{
// GetHitTest is called to see if the point is
// within this glyph. This gives us a chance to decide
// what cursor to show. Returning null from here means
// the mouse pointer is not currently inside of the glyph.
// Returning a valid cursor here indicates the pointer is
// inside the glyph, and also enables our Behavior property
// as the active behavior.
if (Bounds.Contains(p))
{
return Cursors.Hand;
}
return null;
}
public override void Paint(PaintEventArgs pe)
{
// Draw our glyph. It is simply a blue ellipse.
pe.Graphics.DrawEllipse(Pens.Blue, Bounds);
}
// By providing our own behavior we can do something interesting
// when the user clicks or manipulates our glyph.
class ShowTabBehavior : Behavior
{
public override bool OnMouseUp(Glyph g, MouseButtons button)
{
//MessageBox.Show("Hey, you clicked the mouse here");
//this.
ShowTabGlyph myG = (ShowTabGlyph)g;
if (myG.Callback != null)
{
myG.Callback();
}
return true; // indicating we processed this event.
}
}
}
}
[DesignerAttribute(typeof(TabButtonDesigner))]
public class MyCustomTabButton : System.Windows.Forms.Button
{
// The attribute will assign the custom designer to the TabButton
// and after a rebuild the button contains a centered blue circle
// that acts at design time like the button in runtime does ...
// ...
}

display image on mouseover in windows form?

I am working on a project in c# using windows forms.
me and the group I am in want to make it so that when the user hovers their mouse over an image, in our case a card, that a larger image of that card appears next to the mouse arrow, much in the same way a tool tip would work.
I don't think you can use a tool tip to do this i have tried looking everywhere,
any advice or examples would be great thank you very much
You may want to look at this Code Project Article
It shows you how to create an OwnerDrawn ToolTip with an Image.
Thanks for the responses I got everything figured out.
What I wanted to do was that when I moused over a certain area a different image for that area would popup in the same way that a tool tip did. So after some research I figured out how to create my own tool tip class.
here's an example.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
CustomToolTip tip = new CustomToolTip();
tip.SetToolTip(button1, "text");
tip.SetToolTip(button2, "writing");
button1.Tag = Properties.Resources.pelican; // pull image from the resources file
button2.Tag = Properties.Resources.pelican2;
}
}
class CustomToolTip : ToolTip
{
public CustomToolTip()
{
this.OwnerDraw = true;
this.Popup += new PopupEventHandler(this.OnPopup);
this.Draw +=new DrawToolTipEventHandler(this.OnDraw);
}
private void OnPopup(object sender, PopupEventArgs e) // use this event to set the size of the tool tip
{
e.ToolTipSize = new Size(600, 1000);
}
private void OnDraw(object sender, DrawToolTipEventArgs e) // use this to customzie the tool tip
{
Graphics g = e.Graphics;
// to set the tag for each button or object
Control parent = e.AssociatedControl;
Image pelican = parent.Tag as Image;
//create your own custom brush to fill the background with the image
TextureBrush b = new TextureBrush(new Bitmap(pelican));// get the image from Tag
g.FillRectangle(b, e.Bounds);
b.Dispose();
}
}
}
A simple way to do is to hide/show a picture box at specified location. Another method is to load & draw (paint) an image using GDI API.

Categories