I have sets of web hosted images that I need my user to be able to select 1 from each. I thought a listbox would work for this, but I can't figure out add an image to one. Is this possible? better way of doing this? I am using the latest free vb.
Use the Listview control instead, it provides better functionality, and doesn't suffer from an annoying resize bug. The listbox is carried over from VB6 days. The listview supports column headers, groupings and a bit more.
Add a Imagelist control to your form, to store the images; set it's ColorDepth property to 32-bit, and set the Listview's LargeImagelist property to the imagelist control you just added (this can all be done in code as well).
Add images to the Imagelist via this code:
ImageList1.Images.Add("imagekey", Image.FromStream(yourimagestream))
Add items to the Listview via this code:
ListView1.Items.Add("list item title", "imagekey")
The "imagekey" is a way to tell the Listview which image to use. You can also use indexes for icons, but specifying an index that doesn't exist will give an index out of range exception, whereas a key that doesn't exist, will just use no image instead.
Oh you also want to set the Listview Multiselect property to False (if you only want them to select one at a time), and access the SelectedIndexChanged() and ItemActivate() events for when the user clicks / double-clicks on items respectively.
Set ListBox1.DrawMode to DrawMode.OwnerDrawFixed or DrawMode.OwnerDrawVariable, and add a handler for drawing the images.
Private Sub listBox1_DrawItem(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles ListBox1.DrawItem
Dim img As Image
img = sender.items(e.Index)
e.Graphics.DrawImage(img, targetsize)
End Sub
You can add the images to the listbox items collection.
Dim img As Image
img = Image.FromFile("c:\tmp.jpg") ' or whatever
ListBox1.Items.Add(img)
...
Yes, this is possible:
Dim imgList As New ImageList
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
ListView1.View = View.Details
ListView1.Width = 500
ListView1.Columns.Add("Gender", 75, HorizontalAlignment.Left)
ListView1.Columns.Add("Name", 100, HorizontalAlignment.Left)
ListView1.Columns.Add("Notes", 350, HorizontalAlignment.Left)
ListView1.AllowColumnReorder = True
ListView1.Columns(0).DisplayIndex = 1
imgList.Images.Add("Male", Image.FromFile("C:\Users\Joe\Pictures\Male-Symbol.jpg"))
imgList.Images.Add("Female", Image.FromFile("C:\Users\Joe\Pictures\Female-Symbol.jpg"))
ListView1.SmallImageList = imgList
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim index As Integer
Select Case True
Case RadioButton1.Checked
index = 0
Case RadioButton2.Checked
index = 1
End Select
Dim lvi As New ListViewItem
lvi.ImageIndex = index
lvi.SubItems.Add(TextBox1.Text)
ListView1.Items.Add(lvi)
End Sub
To resize the image use:
imgList.ImageSize = New Size(100, 14)
Related
Now what i was doing is when i click a button group box 1 and group box 2 will show out i want to select the combobox item than the picturebox item will load
and this can be used it multiple time like when button-5 clicked the combobox item name will change and the picture will change too.
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
GroupBox1.Show()
GroupBox2.Show()
comboboxselectdiffrent.Items.Add("pizza_ChickenSupreme")
comboboxselectdiffrent.Items.Add("pizza_CockadoodleBacon")
If comboboxselectdiffrent.SelectedIndex = 0 Then
PictureBox1.Image = PIZZA_HUT_SYSTEM_NEW_VER.My.Resources.Resources.pizza_ChickenSupreme
ElseIf comboboxselectdiffrent.SelectedIndex = 1 Then
PictureBox1.Image = PIZZA_HUT_SYSTEM_NEW_VER.My.Resources.Resources.pizza_CockadoodleBacon
End If
End Sub
Can anyone tell me what i was do wrong? i have no idea why it wont work
After looking at your code personality I would have the event trigger from the combobox click, that way it will save the user having to first click on the combo to select their pizza and then having to click on a button to load the picture & details. Nevertheless try this.
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ComboBox1.Items.Add("pizza_ChickenSupreme")
ComboBox1.Items.Add("pizza_CockadoodleBacon")
ComboBox1.DropDownStyle = ComboBoxStyle.DropDownList
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
GroupBox1.Show()
GroupBox2.Show()
Select Case ComboBox1.SelectedItem
Case Is = "pizza_ChickenSupreme"
PictureBox1.ImageLocation = "Pictures/mypic.jpg"
Case Is = "pizza_CockadoodleBacon"
PictureBox1.ImageLocation = "Pictures/mypic1.jpg"
End Select
End Sub
End Class
Using a custom Folder within the solution explorer will be better than using a setting resource. Create a folder and drag your pictures into it and change the name of the image location to suit your needs.
Also i think using the items name is better than the items index because what happens if someone reason that indexed item is to change from 1 to 5, you would have to recode it all, but by using the items name, it has more detail as to what to look for.
If you have any problems, leave a comment and I will do my best to help you out.Happy Coding!
I have a listview that lists all items from a directory like so:
But as you can see in this image:
They are not in order, because one image text has been skipped entirely, however the image itself is still in order.
But, when it gets further down the list, starting from about half way they start becoming completely mixed up like in this example:
Image 3
When clicking an image it shows the preview of the correct image on the right side.
image 4
This is the code I'm using to load in all the images:
Dim imgList As New ImageList
Dim imgSize As New Size
Dim count As Integer = 0
Dim imgFilename As String
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'Dim imlTemp As New ImageList
Dim dirFiles() As String = IO.Directory.GetFiles(My.Settings.GalleryLocation)
'Dim item As New ListViewItem
For Each dirFile As String In dirFiles
imgFileName = IO.Path.GetFileName(dirFile)
Dim img As New System.Drawing.Bitmap(dirFile)
Dim imgImage As Image = Image.FromFile(dirFile)
'Dim imgHeight As Integer
'imgHeight = imgImage.Height
imgSize.Width = 120
imgSize.Height = 174
Threading.Thread.Sleep(10)
BackgroundWorker1.ReportProgress(100 / ((dirFiles.Count + 1) - count), img)
Next
End Sub
Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
ListView1.SmallImageList = imgList
ListView1.LargeImageList = imgList
imgList.ImageSize = imgSize
imgList.ColorDepth = ColorDepth.Depth32Bit
ListView1.Items.Add(imgFilename, count)
imgList.Images.Add(e.UserState.Clone)
count += 1
'ListView1.EnsureVisible(ListView1.Items.Count - 1)
End Sub
Before I added in the backgroundworker it had tremendous loading times for a large amount of images, so I thought I'd implement the backgroundworker to allow async work to be done. However, something is going completely wrong at the start of the task and multiple times part way through the list, where it completely messes up as shown in Image 3.
Does anybody have any idea what is going wrong, or any alternative solutions to what I'm aiming to do?
Since ReportProgress() is not blocking (as far as I know), there is a chance that the files are iterated though faster than the UI can update.
To keep this synchronized you should make a custom class holding everything you want to update and pass that to the ReportProgress() method (even making some steps automated).
For example:
Public Class GalleryImage
Public Property FullPath As String
Public Property FileName As String
Public Property [Image] As Image
Public Sub New(ByVal File As String)
Me.Image = Image.FromFile(File) 'Get the image.
Me.FullPath = File 'Save the full path of the image.
Me.FileName = Path.GetFileName(File) 'Get the file name.
End Sub
End Class
(Also, if you want the file name but not the extension you can use Path.GetFileNameWithoutExtension())
Now to your code. First of all the counter variable isn't really necessary as it can be replaced by either ListView1.Items.Count or imgList.Images.Count.
Secondly, you shouldn't constantly keep setting the imgSize variable nor the ListView's Small-/LargeImageList properties. Doing that is completely unnecessary and will slow things down. For the ListView just set the image list once, and for the imgSize variable you can do like this:
Dim ReadOnly imgSize As New Size(120, 174)
Making the variable ReadOnly does what it sounds like; you can read from it, but not modify it.
Now to fix these other things we'll start in the BackgroundWorker's For Each loop:
For Each dirFile As String In dirFiles
Threading.Thread.Sleep(10) 'You don't need this Sleep if you don't want to.
'Report the progress, declare an in-line version of our class and send it with.
BackgroundWorker1.ReportProgress(100 / ((dirFiles.Count + 1) - ListView1.Items.Count), New GalleryImage(dirFile)) 'A new GalleryImage is created. The property setting is handled by the class itself.
Next
As you see we have now narrowed the code down rather much.
Now we are going to handle the ReportProgess() event:
Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
Dim img As GalleryImage = e.UserState 'Retrieve our class, no need to clone it.
imgList.Images.Add(img.Image) 'Add the image first (I don't know for sure, but if you add the image after, wouldn't it require to redraw the ListView an extra time?).
ListView1.Items.Add(img.FileName, imgList.Images.Count - 1) 'Add the new item with the values from our class.
End Sub
And lastly, the initialization and initial setting of stuff should be done in for example the Form Load event:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'In here we do all the standard settings and initializations.
ListView1.SmallImageList = imgList
ListView1.LargeImageList = imgList
imgList.ImageSize = imgSize
imgList.ColorDepth = ColorDepth.Depth32Bit
End Sub
And by that I think I should have covered it all.
Hope this helps!
First of all, i did make a combox box with ownerdrawvariable mod because i wanted to handle a tooltips with the mouse hover. To do this i handled two methods DrawItem and MeasureItem :
Private Sub DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles cboPneuGlobal.DrawItem
If e.Index = -1 Then
Exit Sub
End If
e.DrawBackground()
Dim p As Point = New Point(CInt(cboPneuGlobal.Location.X * Ratio), CInt(cboPneuGlobal.Location.Y * Ratio))
Dim brColor As Brush = Brushes.Black
If e.State = DrawItemState.Selected Then
ToolTipFormBase.Show(CType(cboPneuGlobal.Items(e.Index), clsPneuEtTypeMarque).ToDisplay, Me, p)
brColor = Brushes.White
End If
e.Graphics.DrawString(CType(cboPneuGlobal.Items(e.Index), clsPneuEtTypeMarque).ToDisplay, e.Font, brColor, New Point(e.Bounds.X, e.Bounds.Y))
End Sub
Here the second :
Private Sub measureItem(ByVal sender As Object, ByVal e As System.Windows.Forms.MeasureItemEventArgs) Handles cboPneuGlobal.MeasureItem
' fetch the current item we’re painting as specified by the index
Dim comboBoxItem As Object = cboPneuGlobal.Items(e.Index)
' measure the text of the item (in Whidbey consider using TextRenderer.MeasureText instead)
Dim textSize As Size = e.Graphics.MeasureString(CType(cboPneuGlobal.Items(e.Index), clsPneuEtTypeMarque).ToDisplay, cboPneuGlobal.Font).ToSize()
e.ItemHeight = textSize.Height
e.ItemWidth = textSize.Width
End Sub
I got a small display problem which the combo box height doesn't follow the font of my item and stay small. That make my text truncate. See the image :
What i'm doing wrong ??
It's work great with a non ownerdraw combobox
When I load the form where some text has been given to text box. All the text in that textbox is highlighted. I want vb not to load it this way.
How to fix it.
Thanks
Furqna
You could set the tab index on your textbox to something else so that it's not the lowest index.
You could set the TextBox1.SelectionLength = 0 in the form.activated event.
I don't like this as much because if the user had the text hilited and minized the application then they will lose the hilite, but is fairly easy to do. I guess you could use a flag to make sure it only did it on the first activate.
You could set a timer event in the load to clear it immediately after the load event, but that seems like overkill. I have worked at places where they had a standard function that happened on every form 100 ms after load because of problems such as this.
You could try this(it looks like a workaround):
Private Sub TextBox1_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.GotFocus
TextBox1.SelectionStart = TextBox1.Text.Length
End Sub
It depends on the TabIndex of your TextBox, if it has the lowest TabIndex it gets focus and therefore it's Text is selected.
' VS.net 2013. Use the "Shown" event.
' GotFocus isn't soon enough.
Private Sub Form_Shown(sender As Object, e As EventArgs) Handles Me.Shown
TB.SelectionLength = 0
End Sub
Type 1 Method
Dim speech = CreateObject("sapi.spvoice")
speech.speak(TextBox1.Text)
Type 2 Method
Dim oVoice As New SpeechLib.SpVoice
Dim cpFileStream As New SpeechLib.SpFileStream
'Set the voice type male or female and etc
oVoice.Voice = oVoice.GetVoices.Item(0)
'Set the voice volume
oVoice.Volume = 100
'Set the text that will be read by computer
oVoice.Speak(TextBox1.Text, SpeechLib.SpeechVoiceSpeakFlags.SVSFDefault)
oVoice = Nothing
Type 3 Method
Imports System.Speech.Synthesis
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim spk As New SpeechSynthesizer
For Each voice As InstalledVoice In spk.GetInstalledVoices
ListBox1.Items.Add(voice.VoiceInfo.Name)
Next
ListBox1.SelectedIndex = 0
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim spk As New SpeechSynthesizer
spk.SelectVoice(ListBox1.SelectedItem.ToString)
spk.Speak(TextBox1.Text)
End Sub
End Class
This will also happen sometimes if The TextChanged or other similar Event is fired twice for the control.
When creating each form. Each object is indexed you can set the tab Index higher then the indexed object. Example: On the third form you put a text box in.
private void textBox1_TextChanged(object sender, EventArgs e)
This was the 12th object in the project, it would be indexed at 12. if you put the tab index higher then the indexed objects throughout the project. Tab index 1000 (problem solved.)
Have a great day.
Scooter
I am attempting to move all controls on a form down or up by the height of a menubar depending on whether it is visible or not. I have code which I think ought to work well for this, however it seems that Me.Controls is empty at runtime, so my for each loop is never entered. Could someone please offer a suggestion as to how I can move the controls?
Private Sub uxMenuStrip_VisibleChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles uxMenuStrip.VisibleChanged
For Each control As Control In Me.Controls
If control.Name <> "uxMenuStrip" Then
Dim temp As AnchorStyles = control.Anchor
control.Anchor = AnchorStyles.None
control.Top -= ((CInt(uxMenuStrip.Visible) * 2 - 1) * uxMenuStrip.Height)
control.Anchor = temp
End If
Next
Me.Height += ((CInt(uxMenuStrip.Visible) * 2 - 1) * uxMenuStrip.Height)
End Sub
Add a new Handler with Control and change location in address
Public Sub ChngPostion(ByVal sender As System.Object, ByVal e As System.EventArgs)
For Each cntrl As Control In Me.Controls
If cntrl.Name = sender.Name Then
cntrl.Location = New System.Drawing.Point(sender.Location.X,sender.Location.Y)
End If
Next
End Sub
As Michael Todd points out, Me.Controls can't be empty. Also, this might not work as well as you're thinking. Controls on WinForms apps are hierarchical. The only way to do this 100% cleanly is to make the move code recursive. IE, perform the same operation on every control in each control's controls collection. (Now I'm sounding like Dr. Seuss...) If your form is simple, this wouldn't be an issue, obviously.
At the end of the day, though, you'll probably be better off just putting everything on the form inside a Panel and just moving the Panel control explicitly by name. It would make what you're trying to do more clear.
Try this:
Private Sub uxMenuStrip_VisibleChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles uxMenuStrip.VisibleChanged
Dim menu As Control = sender
Dim dh As Integer = IIf(menu.Visible, 1, -1) * menu.Height
For Each control As Control In Controls
If control.Parent Is Me And Not control Is menu Then
control.Top += dh
End If
Next
Height += dh
End Sub
Update:
Anyway, i strongly recomment using container, in case with MenuStrip - ToolStripContainer.