I am using c# and winForms to create an application that allows me to have 6 Picture Boxes (each with a different image) on top of one another. Each image has alot of white space so i am trying to use transparency to allow the user to toggle images on and off. When an image is toggled off, the parent/child of all the other images will be updated to allow the transparency to work.
I First created a custom class:
public class MyImageWrapper
{
public MyImageWrapper Parent { get; set; }
public PictureBox PictureBox { get; set; }
public MyImageWrapper(PictureBox i, MyImageWrapper parent = null)
{
Parent = parent;
PictureBox = i;
}
}
Then I Created the Array:
MyImageWrapper[] pictureBoxArray = new MyImageWrapper[6];
This next code is a test to Check if transparency works:
pictureBox[0] = new MyImageWrapper(pictureBox1);
pictureBox[1] = new MyImageWrapper(pictureBox2);
pictureBox1.Image = (Image.FromFile(""+ Application.StartupPath +"../../../images/imageA.png"));
pictureBox2.Image = (Image.FromFile(""+ Application.StartupPath +"../../../images/imageB.png"));
pictureBoxArray[1].Parent = pictureBoxArray[0];
Unfortunately I do not receive any error messages so it seems to be working. However when I run the program Picture Box 2 is not a child of picture box 1 (and thus transparency does not work)
I have not gotten as far as setting the images to be turned on or off yet, I am still trying to sort out the transparency.
The problem specifically is this line:
pictureBoxArray[1].Parent = pictureBoxArray[0];
When testing I replaced the above line with:
pictureBox2.Parent = pictureBox1;
This does exactly the same thing (but works!). However the way my program needs to work later I cannot do it like this. I need to fix the Array version.
Any help would be greatly appreciated.
Wouldn't you need to put:
pictureBoxArray[1].PictureBox.Parent = pictureBoxArray[0].PictureBox
?
The two lines:
pictureBoxArray[1].Parent = pictureBoxArray[0];
pictureBox2.Parent = pictureBox1;
You have put are not equivalent. In one you are assigning the parent of the ImageWrapper and in the other you are assigning the parent of the PictureBox.
I don't know if this is an error in how you have presented the code or in your program itself.
Related
I am trying to check if a PictureBox contains a certain image, the way I am trying to do it seems like it would work in my head, however, does not, i am not sure if there is any other way to check if the picturebox on the form contains a certain image.
private void user_btn_Click(object sender, EventArgs e)
{
//If statement to check if the forms picture box contains a certain image
if (pictureBox1.Image == Resources.user_male_white_red_brown)
{
this.Hide();
UserProfile User = new UserProfile();
User.ShowDialog();
User.pictureBox1.Image = Resources.user_male_white_red_brown;
this.Close();
}
else if (pictureBox1.Image == Resources.user_female_olive_orange)
{
this.Hide();
UserProfile User = new UserProfile();
User.ShowDialog();
User.pictureBox1.Image = Resources.user_female_olive_orange;
this.Close();
}
}
Although PictureBox Image might be identical as the one in the resources but they are not the same as reference. (Imagine like you have 2 copy of the same photo although their image is the same but they are 2 separate photos).
There are a few ways you can do it, one of them (a simple one) is to set the picturebox Tag to a relevent value whenever setting its image and compare that value instead of comparing images:
User.pictureBox1.Image = Resources.user_male_white_red_brown;
User.pictureBox1.Tag = "user_male_white_red_brown";
And then:
if((string)User.pictureBox1.Tag == "user_male_white_red_brown")
{
// your logic
}
This way you need to set PictureBox tag whenever you set its image.
Another way would be loading all images from resources to an array and setting the PictureBox image from the array, this way as the reference of both images (picturebox.Image and the image item in the array) are the same comparison would work for images but I think the first solution is easier.
I am making a library management software. This is the screenshot:
I have implementing functionalities like dragging a book into the delete icon to delete the book. But there are two obstacles:
DataPackageOperation has only four possibilities: Copy, link, move none. So, after four, it is difficult to differentiate which AppBarButton is the book dropped on.
I plan to add more items to the CommandBar. But there are only four possible operations
I need a way to give the user a custom feedback as to which AppBarButton is the book currently dragged over. DataPackageOperation contains only four. Out of which, 'None' cannot be used(because it will be confusing). Is there a way to provide that feedback?
I need a way to give the user a custom feedback as to which AppBarButton is the book currently dragged over
You could give the user a custom feedback via custom Drag UI. The follow code comes from XamlDragAndDrop official code sample.
private void TargetTextBox_DragEnter(object sender, Windows.UI.Xaml.DragEventArgs e)
{
/// Change the background of the target
VisualStateManager.GoToState(this, "Inside", true);
bool hasText = e.DataView.Contains(StandardDataFormats.Text);
e.AcceptedOperation = hasText ? DataPackageOperation.Copy : DataPackageOperation.None;
if (hasText)
{
e.DragUIOverride.Caption = "Drop here to insert text";
// Now customize the content
if ((bool)HideRB.IsChecked)
{
e.DragUIOverride.IsGlyphVisible = false;
e.DragUIOverride.IsContentVisible = false;
}
else if ((bool)CustomRB.IsChecked)
{
var bitmap = new BitmapImage(new Uri("ms-appx:///Assets/dropcursor.png", UriKind.RelativeOrAbsolute));
// Anchor will define how to position the image relative to the pointer
Point anchor = new Point(0,52); // lower left corner of the image
e.DragUIOverride.SetContentFromBitmapImage(bitmap, anchor);
e.DragUIOverride.IsGlyphVisible = false;
e.DragUIOverride.IsCaptionVisible = false;
}
// else keep the DragUI Content set by the source
}
}
So I'm trying to make a matching game in WinForms with C#. I looked at this MSDN project: https://msdn.microsoft.com/en-us/library/dd553230.aspx. I replaced the icon list with an imagelist. According to this article my images should show up twice per image. But whenever it hits the same number again it says that it's out of bounds, this is what I think is happening. Here is my code:
public frmMain()
{
InitializeComponent();
imageInit();
imgToLbl();
}
Random rndImage = new Random();
ImageList images = new ImageList();
//list of file names
List<string> files = new List<string>()
{
"Bavaria", "Denemarken", "Engeland",
"Frankrijk", "Nederland", "oostenrijk",
"Polen", "Pruissen", "Rusland", "Schotland",
"Spanje", "Zweden"
};
// Method to put the files into the imagelist
private void imageInit()
{
for(int i = 0; i < 12; i++)
{
images.Images.Add(files[i], Image.FromFile("../../images/" + files[i] + ".png"));
}
}
// method to assign the images to a label in my form
private void imgToLbl()
{
foreach (Control ctrl in tableLayoutPanel1.Controls)
{
Label imgLbl = ctrl as Label;
if (imgLbl != null)
{
int rndNum = rndImage.Next(images.Images.Count);
images.ImageSize = imgLbl.Size;
imgLbl.ImageList = images;
imgLbl.ImageIndex = rndNum;
imgLbl.ImageList.Images.RemoveAt(rndNum);// this is where the exception is being thrown
}
}
}
Here is the full exception:
An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in System.Windows.Forms.dll
Additional information: InvalidArgument=Value of '8' is not valid for 'index'.
I have a feeling that this should be easy but I can't figure out how to fix this exception. There's also another thing. The colors are all messed up and I don't know why.
Here is the original:
Here is the messed up one which is being shown in the app:
Can someone please help me?
It looks like you're trying to remove the images from the Labels ImageList that you've just assigned to it. You will eventually end up with 0 entries in the ImageList and Labels still referencing indexes. your assignment of imgLbl.ImageList is a reference to the already existing ImageList object, it is not cloning it and as such when you remove an entry from its list it is removing it for every label already assigned the instance. You want to clone the list (or better yet) maintain 1 full list and ensure you dont pick the same number twice.
You are destroying the images in the ImageList but you still want the Lables, ListItems etc.. to refer to them. This can't work
You need to keep them around as long as any control or other item needs to display them.
You see that you are assigning just a number as the ImageIndex. This number points into the ImageList and therefore the image still needs to be there..
Also: The quality is limited by your choice of images.ColorDepth. Set it to Depth32Bit! The default is only Depth8Bit
I am using Xamarin and C# but I suspect the problem is equally valid in a Java environment.
I have an ActionBar Activity that hosts three tabs each of which hosts a fragment. It uses a ViewPager to allow the user to swipe between the tabs.
The requirement is to programmatically screenshot each tab and then email these as attachments.
The problem is that whilst the ActionBar/ViewPager works well it also optimises the tabs - effectively it isn't creating a fragment's view until it is next in line to be shown. So, if you're on tab 0 - the first tab - then the fragment view for tab 2 is null. So it can't be screenshot.
To overcome this I have tried to set any tab/fragment that has a null view to be selected. This generates the view but because setting it to be selected does not actually render it on screen the view does not have a width or a height value so again it cannot be screenshot (this is the reason for the defensive check at the start of the code taking the screenshot).
So, I guess my question is how can I force the tab to be rendered on screen so that it is correctly filled out and can be screenshot?
My main code extracts are as follows:
private void EmailReport()
{
List <Bitmap> bitmaps = new List<Bitmap>();
List <string> summaryFiles = new List<string>();
// remember the tab we're on
var selectedTab = this.ActionBar.SelectedNavigationIndex;
// take the screenshots
for (int fragmentNumber = 0; fragmentNumber < projectFragmentPagerAdapter.Count; fragmentNumber++)
{
Android.Support.V4.App.Fragment fragment = projectFragmentPagerAdapter.GetItem(fragmentNumber);
if (fragment.View == null)
{
this.ActionBar.GetTabAt(fragmentNumber).Select();
fragment = projectFragmentPagerAdapter.GetItem(fragmentNumber);
}
bitmaps.Add(ScreenShot(fragment.View));
}
// set the active tab back
this.ActionBar.GetTabAt(selectedTab).Select();
//write the screenshots into file
int i = 0;
foreach(Bitmap bitmap in bitmaps)
{
if (bitmap != null)
summaryFiles.Add(BitmapToFile(bitmap, this.ActionBar.GetTabAt(i).Text));
i++;
}
// now send the file
EmailSupport.SendAttachments(this, summaryFiles);
}
private Bitmap ScreenShot(View fragmentRootView)
{
if (fragmentRootView == null || fragmentRootView.Width == 0 || fragmentRootView.Height == 0)
return null;
fragmentRootView.DrawingCacheEnabled = true;
//create a bitmap for the layout and then draw the view into it
Bitmap bitmap = Bitmap.CreateBitmap(fragmentRootView.Width, fragmentRootView.Height,Bitmap.Config.Argb8888);
Canvas canvas = new Canvas(bitmap);
//Get the view's background
Drawable bgDrawable = fragmentRootView.Background;
if (bgDrawable!=null) // has background drawable, then draw it on the canvas
bgDrawable.Draw(canvas);
else // does not have background drawable, then draw white background on the canvas
canvas.DrawColor(Color.White);
// draw the view on the canvas
fragmentRootView.Draw(canvas);
fragmentRootView.DrawingCacheEnabled = false;
return bitmap;
}
Any help would be gratefully received.
The solution in the end was very simple. The ViewPager has a setting controlling the number of pages (fragments) that it will hold "activated". This defaults to 1. As I had 3 tabs this meant there was always one tab (fragment) out of reach.
So, whilst setting up the ViewPager do the following before the tabs are added:
reportViewPager.OffscreenPageLimit = pageCount - 1;
Or in Java
reportViewPager.setOffscreenPageLimit(pageCount - 1);
I hope this helps someone else avoid wasting hours.
I've got a StatusStrip with a single ToolStripStatusLabel, Spring=true and a background color for notifications.
The problem is that there's an ugly gray square on the right side of the status strip. After fiddling for a while, I realized this is the sizing grip (I had is set to SizingGrip=false, GripStyle=Hidden). Yet even with it hidden, it still hogs the space. I can't get any content on the status strip to extend all the way to the right.
How would you work around this? Note I can't just set the backcolor of the StatusStrip because the Status Label changes colors and has some fading effects.
The StatusStrip.Padding property is borked, it returns the wrong value for Padding.Right if the sizing grip is disabled. You can fix it in your form constructor, like this:
public Form1() {
InitializeComponent();
statusStrip1.Padding = new Padding(statusStrip1.Padding.Left,
statusStrip1.Padding.Top, statusStrip1.Padding.Left, statusStrip1.Padding.Bottom);
}
Using the Left property to specify Right is the fix. Don't bother submitting this bug to Connect, they won't fix it.
Have a look at this blog entry on MSDN. The question was about changing the size of the sizing grip manually, and I think using the ToolStrip Renderer as suggested could work for you also.
The problem I have so far, is that it removes the background color on a status label in the StatusStrip, so it's not a solution yet, but it's a start.
public MyForm()
{
InitializeComponent();
statusStrip1.Renderer = new MyRenderer();
}
private class MyRenderer : ToolStripProfessionalRenderer
{
protected override void OnRenderStatusStripSizingGrip(ToolStripRenderEventArgs e)
{
// don't draw at all
}
}
I had following problem: when I set tsslSeparator.Spring = true, my right label disappeared immediately after tsslSeparator lost focus. The issue appeared when sizing grip was enabled. When it was disabled, everything worked just fine.
The solution was to set right margin for right label to something different than 0.
tsslLogging.Margin = new Padding(0, 3, 2, 2); // this is necessary for right alignment of status bar label
Hope this helps somebody.
If Microsoft isn't interesting in fixing it, it seems like a proper fix should handle all orientations, and ideally fix all Status Strips (see my answer to Get All Children for definition of GetAllChildren)
public static StatusStrip FixPadding(this StatusStrip ss) {
if (!ss.SizingGrip) {
var fixpad = ss.Padding;
if (ss.Orientation == Orientation.Horizontal) {
if (ss.RightToLeft == RightToLeft.No)
fixpad.Right = fixpad.Left;
else
fixpad.Left = fixpad.Right;
}
else
fixpad.Bottom = fixpad.Top;
ss.Padding = fixpad;
}
return ss;
}
public static void FixStatusStripPadding(this Form f) {
foreach (var ss in f.GetAllChildren().OfType<StatusStrip>())
ss.FixPadding();
}