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
Related
I want to do something seemingly simple - programmatically select and highlight a row of a ListView in VB.NET.
VB.NET: How to dynamically select a list view item?
tells me what should to be all that is needed, but it isn't. The row is selected, but not highlighted.
http://vbcity.com/forums/t/28260.aspx
tells me about the "HideSelection" property and the .Focus() method (also referenced at Select programmatically a row of a Listview), which sounded hopeful, but the best I can get is the faint highlight mentioned, I want the full monty. I tried a Noddy example with just a ListView, in Details mode, FullRowSelection = true, HideSelection = False, one columnheader defined and then
ListView1.Items.Add("Red")
ListView1.Items.Add("Orange")
ListView1.Items.Add("Yellow")
ListView1.Items.Add("Green")
ListView1.Items(2).Selected = True
I get this
but I want this
I can simulate highlighting by adding these lines
ListView1.SelectedItems(0).BackColor = Color.CornflowerBlue
ListView1.SelectedItems(0).ForeColor = Color.White
but then how can I be sure to undo the artificial highlight if the row can be implicitly as well as explicitly deselected? Do I have to think of all the possible cases? That's too much work for what should be a simple operation. Plus, since I want to color-code my rows, there is an additional challenge that when I undo the highlight color, I have to figure out what color is appropriate at that point. Is there a better, simpler way?
You can access the Graphics object used to draw each item, and draw them yourself.
Make a new project with a Button and ListView. Paste the following code:
Form_Load to use multiple subitems
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.ListView1.OwnerDraw = True ' or else can't handle DrawItem event
ListView1.Columns.Add("ColumnHeader1")
ListView1.Columns.Add("ColumnHeader2")
ListView1.Columns.Add("ColumnHeader3")
Me.ListView1.Items.Add("Red")
Me.ListView1.Items.Add("Orange")
Me.ListView1.Items.Add("Yellow")
Me.ListView1.Items.Add("Green")
ListView1.Items(0).SubItems.Add("Strawberry")
ListView1.Items(0).SubItems.Add("Apple")
ListView1.Items(1).SubItems.Add("Pepper")
ListView1.Items(1).SubItems.Add("Apricot")
ListView1.Items(2).SubItems.Add("Plum")
ListView1.Items(2).SubItems.Add("Banana")
ListView1.Items(3).SubItems.Add("Apple")
ListView1.Items(3).SubItems.Add("Lime")
End Sub
Three handlers for the ListView's drawing related events. Code copied from this answer
Private Sub listView1_DrawColumnHeader(sender As Object, e As DrawListViewColumnHeaderEventArgs) Handles ListView1.DrawColumnHeader
e.DrawDefault = True
End Sub
Private Sub listView1_DrawSubItem(sender As Object, e As DrawListViewSubItemEventArgs) Handles ListView1.DrawSubItem
Const TEXT_OFFSET As Integer = 1
' I don't know why the text is located at 1px to the right. Maybe it's only for me.
Dim listView As ListView = DirectCast(sender, ListView)
' Check if e.Item is selected and the ListView has a focus.
If Not listView.Focused AndAlso e.Item.Selected Then
Dim rowBounds As Rectangle = e.SubItem.Bounds
Dim labelBounds As Rectangle = e.Item.GetBounds(ItemBoundsPortion.Label)
Dim leftMargin As Integer = labelBounds.Left - TEXT_OFFSET
Dim bounds As New Rectangle(rowBounds.Left + leftMargin, rowBounds.Top, If(e.ColumnIndex = 0, labelBounds.Width, (rowBounds.Width - leftMargin - TEXT_OFFSET)), rowBounds.Height)
Dim align As TextFormatFlags
Select Case listView.Columns(e.ColumnIndex).TextAlign
Case HorizontalAlignment.Right
align = TextFormatFlags.Right
Exit Select
Case HorizontalAlignment.Center
align = TextFormatFlags.HorizontalCenter
Exit Select
Case Else
align = TextFormatFlags.Left
Exit Select
End Select
TextRenderer.DrawText(e.Graphics, e.SubItem.Text, listView.Font, bounds, SystemColors.HighlightText, align Or TextFormatFlags.SingleLine Or TextFormatFlags.GlyphOverhangPadding Or TextFormatFlags.VerticalCenter Or TextFormatFlags.WordEllipsis)
Else
e.DrawDefault = True
End If
End Sub
Private Sub listView1_DrawItem(sender As Object, e As DrawListViewItemEventArgs) Handles ListView1.DrawItem
Dim listView As ListView = DirectCast(sender, ListView)
' Check if e.Item is selected and the ListView has a focus.
If Not listView.Focused AndAlso e.Item.Selected Then
Dim rowBounds As Rectangle = e.Bounds
Dim leftMargin As Integer = e.Item.GetBounds(ItemBoundsPortion.Label).Left
Dim bounds As New Rectangle(leftMargin, rowBounds.Top, rowBounds.Width - leftMargin, rowBounds.Height)
e.Graphics.FillRectangle(SystemBrushes.Highlight, bounds)
Else
e.DrawDefault = True
End If
End Sub
Button click handler to simulate item(2) selected
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.ListView1.Items(2).Selected = True
End Sub
This will draw the background color regardless of focus. You have a lot of control over other colors and fonts going this route too.
Here, the button has been clicked, to select item 2, while the button still has focus, and item 2 is selected.
Easiest thing,
Just allocate the LST_ItemIndex = lstList.FocusedItem.Index everytime you select a different item
and then fire the below whenever you want the highlight
If lstList.Items.Count > 0 Then
lstList.Items(LST_ItemIndex).Selected = True
lstList.Items(LST_ItemIndex).EnsureVisible()
End If
I have a bit of code where i have a dynamically created array or buttons with staff pictures on them, as well as the staff's name. I've added one handler to handle any button click from any of the buttons. where i am stuck is, if you look at the code below, it all works fine, and if you click any of the buttons you get the "aha" test message. but i want the name of the staff clicked on (so btnArray(i).Text) to be passed to the handler for further processing. I tried adding a ByVal parameter to the handler but that caused an error. what's the correct way to do this? As i said, the code below works for me, i just am at a loss as to how to add the extra functionality.
Dim btnArray(staffcount) As System.Windows.Forms.Button
For i As Integer = 1 To staffcount - 1
btnArray(i) = New System.Windows.Forms.Button
btnArray(i).Visible = True
btnArray(i).Width = 80
btnArray(i).Height = 101
btnArray(i).BackgroundImage = Image.FromFile(picloc(i))
btnArray(i).BackgroundImageLayout = ImageLayout.Stretch
btnArray(i).Text = staffname(i)
Dim who As String
who = btnArray(i).Text
AddHandler btnArray(i).Click, AddressOf Me.theButton_Click
btnArray(i).ForeColor = Color.White
btnArray(i).TextAlign = ContentAlignment.BottomCenter
Dim fnt As Font
fnt = btnArray(i).Font
btnArray(i).Font = New Font(fnt.Name, 10, FontStyle.Bold)
FlowLayoutPanel1.Controls.Add(btnArray(i))
Next i
End Sub
Private Sub theButton_Click()
MsgBox("aha")
End Sub
First, correct the signature of your shared handler.
Private Sub theButton_Click(sender As Object, e As EventArgs)
End Sub
Once that is done getting the text of the button clicked is a simple matter.
Private Sub theButton_Click(sender As Object, e As EventArgs)
Dim textOfButtonClicked As String = DirectCast(sender, Button).Text
MessageBox.Show(textOfButtonClicked)
End Sub
The sender is the button that was clicked. Since signatures use objects for the sender the DirectCast 'changes' it to button and you then can access the .Text property of the button.
If there are more manipulations you want to perform on the clicked button you could do it this way
Private Sub theButton_Click(sender As Object, e As EventArgs)
Dim whBtn As Button = DirectCast(sender, Button) ' get reference to button clicked
Dim textOfButtonClicked As String = whBtn.Text
MessageBox.Show(textOfButtonClicked)
'e.g. change the color
whBtn.BackColor = Color.LightYellow
End Sub
So I'm attempting to create a schedule grid in VB.net (exactly like the scheduler in UTorrent, if anyone is familiar) in a 24x7 layout. I want to be able to click down and drag over a series of squares to change the values of them.
I've been able to find this sample code that mostly works.
Private Sub DataGridView3_MouseHover(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DataGridView3.CellMouseMove
Dim grvScreenLocation As Point = DataGridView3.PointToScreen(DataGridView3.Location)
Dim tempX As Integer = DataGridView.MousePosition.X - grvScreenLocation.X + DataGridView3.Left
Dim tempY As Integer = DataGridView.MousePosition.Y - grvScreenLocation.Y + DataGridView3.Top
Dim hit As DataGridView.HitTestInfo = DataGridView3.HitTest(tempX, tempY)
cellX = hit.RowIndex
cellY = hit.ColumnIndex
TextBox3.Text = cellX
TextBox14.Text = cellY
End Sub
As written, this produces the desired results, however I need to have it only return cellx and celly to the text boxes only when the mouse button is down.
This can be accomplished by handling mouse left button down, mouse move and mouse left button up.
When you receive a mouse left button down event on the grid, record the mouse position and set a flag. In the mouse move handler if the flag is set, highlight all cells between the initial position and the current mouse position. On receiving a mouse left button up (on the grid when the grid is set) commit the cell selection (and clear the flag).
I've used this technique successfully for a fractal zoom.
Here's a rough outline of what you need to do:
Dim isSelecting As Boolean
Dim selectionStart As Point
Protected Overrides Sub OnMouseLeftButtonDown(e As MouseButtonEventArgs)
MyBase.OnMouseLeftButtonDown(e)
Dim position = e.GetPosition(Me)
Dim hit = VisualTreeHelper.HitTest(MyGrid, position)
If hit IsNot Nothing Then
isSelecting = True
selectionStart = position
End If
End Sub
Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
MyBase.OnMouseMove(e)
If isSelecting Then
Dim position = e.GetPosition(Me)
' Update selection
End If
End Sub
Protected Overrides Sub OnMouseLeftButtonUp(e As MouseButtonEventArgs)
MyBase.OnMouseLeftButtonUp(e)
If isSelecting Then
Dim position = e.GetPosition(Me)
' Commit selection
End If
End Sub
This gave me what I wanted.
Private cellX As Integer = 0
Private cellY As Integer = 0
Private Sub DataGridView3_MouseHover(ByVal sender As System.Object, ByVal e As MouseEventArgs) Handles DataGridView3.CellMouseMove
Dim grvScreenLocation As Point = DataGridView3.PointToScreen(DataGridView3.Location)
Dim tempX As Integer = DataGridView.MousePosition.X - grvScreenLocation.X + DataGridView3.Left
Dim tempY As Integer = DataGridView.MousePosition.Y - grvScreenLocation.Y + DataGridView3.Top
Dim hit As DataGridView.HitTestInfo = DataGridView3.HitTest(tempX, tempY)
cellX = hit.RowIndex
cellY = hit.ColumnIndex
If e.Button = Windows.Forms.MouseButtons.Left Then
TextBoxX.Text = cellX
TextBoxY.Text = cellY
DataGridView3.Rows(cellX).Cells(cellY).Style.BackColor = Color.Red
End If
End Sub
I'm using VB2008 Express. And I've been working on a "popup" to select a date range. The DateTimePicker isn't ideal because the purpose is to pick a date range, which will always be one full week, from Sunday through Saturday. The control works just fine and I'm pretty proud of it. My problem has to do with the border added when using ToolstripControlHost for this. I've included a screenshot and my code.
In the code below, assume there exists a button named "btnTimePeriod", below which I desire to show a panel, which contains a few custom items, and the panel's name is "pnlDateRangePicker".
IT WORKS... but it doesn't look right. The panel itself is 147 x 326 pixels, but notice in the attached graphic that it's adding a border around the panel which I don't want. There's a border on the top, bottom, and left... but for some reason the border on the right one is especially large. Although my code doesn't expressly set it, AutoSize = true so I would have expected it to shrink around the panel.
As required, my code already does set ShowCheckMargin and ShowImageMargin false. I haven't included the code for the DrawDateCalander Sub because it's not relevant. I believe even a blank panel would yield the same result. I have no idea where this margin is coming from. Any guidance?
Private Sub btnTimePeriod_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnTimePeriod.Click
Call DrawDateCalendar(DatePart(DateInterval.Month, FirstDisplayedSunday), DatePart(DateInterval.Year, FirstDisplayedSunday))
Call ShowControlBelow(btnTimePeriod, pnlDateRangePicker)
End Sub
Sub ShowControlBelow(ByVal Showbutton As Control, ByVal ShownControl As Control)
Dim PopupContainer As New ToolStripControlHost(ShownControl)
PopupContainer.Margin = New Padding(0)
Dim mnuDropDown As New ContextMenuStrip
mnuDropDown.Padding = New Padding(0)
mnuDropDown.ShowCheckMargin = False
mnuDropDown.ShowImageMargin = False
mnuDropDown.Items.Add(PopupContainer)
ShowMenuBelow(Showbutton, mnuDropDown)
End Sub
Sub ShowMenuBelow(ByVal Showbutton As Control, ByVal WhichMenu As ContextMenuStrip, Optional ByVal AlignRight As Boolean = False)
Dim x As Integer = 0
Dim y As Integer = 0
Dim itscontainer As Control = Showbutton.Parent
x = Showbutton.Location.X
y = Showbutton.Location.Y
If Not itscontainer Is Nothing Then
Do Until TypeOf itscontainer Is Form
x = x + itscontainer.Location.X
y = y + itscontainer.Location.Y
itscontainer = itscontainer.Parent
If itscontainer Is Nothing Then Exit Do
Loop
End If
y = y + Showbutton.Height
If AlignRight = True Then
x = x - WhichMenu.Width + Showbutton.Width
End If
Dim xy As New Point(x, y)
WhichMenu.Show(Showbutton.FindForm, xy)
End Sub
I've never used a ContextMenuStrip for that, and maybe that's the problem.
You can try using a ToolStripDropDown instead:
Private Sub ShowControl(ByVal fromControl As Control, ByVal whichControl As Control)
'\\ whichControl needs MinimumSize set:
whichControl.MinimumSize = whichControl.Size
Dim toolDrop As New ToolStripDropDown()
Dim toolHost As New ToolStripControlHost(whichControl)
toolHost.Margin = New Padding(0)
toolDrop.Padding = New Padding(0)
toolDrop.Items.Add(toolHost)
toolDrop.Show(Me, New Point(fromControl.Left, fromControl.Bottom))
End Sub
Private Sub btnTimePeriod_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnTimePeriod.Click
Call DrawDateCalendar(DatePart(DateInterval.Month, FirstDisplayedSunday), DatePart(DateInterval.Year, FirstDisplayedSunday))
'\\Call ShowControlBelow(btnTimePeriod, pnlDateRangePicker)
Call ShowControl(btnTimePeriod, pnlDateRangePicker)
End Sub
I am developing one vb application. In that I have one list box. I want to add different types of Items. Like Different Colored and differently aligned text(Like one item item is right aligned and one more is left aligned). Can you please tell me how can i do the same.
Thanks.
This is how I did it in one of my projects (the original code is in c#):
Public Class ColoringStepCommandListBox
Inherits CommandListBox
Const ItemHeight As Integer = 20
Public Sub New()
listBox.ItemHeight = ItemHeight
listBox.DrawMode = DrawMode.OwnerDrawFixed
End Sub
Protected Overrides Sub OnDrawItem(sender As Object, e As DrawItemEventArgs)
Const textFormatFlags__1 As TextFormatFlags = TextFormatFlags.EndEllipsis Or TextFormatFlags.PreserveGraphicsClipping Or TextFormatFlags.VerticalCenter
Const colorRectangleWidth As Integer = 100, textLeft As Integer = 110
If e.Index >= 0 Then
'Cast the listbox item to your custom type (ColoringStep in my example).
Dim coloringStep = TryCast(listBox.Items(e.Index), ColoringStep)
e.DrawBackground()
'Do custom coloring and rendering, draw icons etc.
Dim colorRect = New Rectangle(2, e.Bounds.Top + 2, colorRectangleWidth, ItemHeight - 5)
Dim innerRect = New Rectangle(colorRect.Left + 1, colorRect.Top + 1, colorRect.Width - 1, colorRect.Height - 1)
e.Graphics.DrawRectangle(Pens.Black, colorRect)
DrawingHelper.DrawGradient(coloringStep, e.Graphics, innerRect, LinearGradientMode.Horizontal)
'Draw the text (this does not happen automatically any more with owner draw modes).
Dim textRect = New Rectangle(textLeft, e.Bounds.Top, e.Bounds.Width - textLeft, e.Bounds.Height)
TextRenderer.DrawText(e.Graphics, coloringStep.ToString(), e.Font, textRect, e.ForeColor, textFormatFlags__1)
e.DrawFocusRectangle()
End If
End Sub
End Class
I got simple solution for this. Below is the code
Private Sub ListBox1_DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles ListBox1.DrawItem
e.DrawBackground()
Dim textFont As New Font(e.Font.FontFamily, e.Font.Size * 4)
e.Graphics.DrawString(ListBox1.Items(e.Index).ToString(), textFont, New SolidBrush(Color.BlueViolet), RectangleF.op_Implicit(e.Bounds))
e.DrawFocusRectangle()
End Sub
Private Sub listBox1_MeasureItem(ByVal sender As Object, ByVal e As System.Windows.Forms.MeasureItemEventArgs) Handles ListBox1.MeasureItem
e.ItemHeight = e.ItemHeight * 4
End Sub
You can add extra code inside ListBox1_DrawItem method to customize Items