So i'm working on a game. Actually an mmorpg. And right now, I have a friends list, in the form of a listbox. Now what i would like to do is set it up so that if i right click a line in the listbox, it will ask me yes or no, and if yes it will warp me to that player. If the line is blank it wont have the popup asking yes or no.
And to help, the warp command is WarpMeTo Trim$()
For an example, if i had it warp me to something that was in a textbox it would be this WarpMeTo Trim$(textbox.text)
and yes, i do use the above for warping administrators to other players, where you input the name.
Actually, If anyone could just tell me how to "get" the name that is on that line in the listbox, that would be awesome, because I'm thinking of making a totally separate menu pop up when you click a name.
This can be split into 2 parts
Make the listbox select an item on a right click
Show the item text only when it was right clicked
When you right click on an item in a listbox, the item isn't selected
To select the item you will have to simulate the left click via the mouse_event() API
After that you can use the _Click() event to show the item, but you will have to make sure the item was right clicked and not left clicked
'1 form with:
' 1 listbox: name=List1
Option Explicit
Private Declare Sub mouse_event Lib "user32" (ByVal dwFlags As Long, ByVal dx As Long, ByVal dy As Long, ByVal cButtons As Long, ByVal dwExtraInfo As Long)
Private Const MOUSEEVENTF_LEFTDOWN = &H2 ' left button down
Private Const MOUSEEVENTF_LEFTUP = &H4 ' left button up
Private mblnRightClick As Boolean
Private Sub Form_Load()
Dim intIndex As Integer
'initialize no right click
mblnRightClick = False
'fill the listbox with some data
List1.Clear
For intIndex = 1 To 10
List1.AddItem CStr(intIndex)
Next intIndex
End Sub
Private Sub Form_Resize()
List1.Move 0, 0, ScaleWidth, ScaleHeight
End Sub
Private Sub List1_Click()
If mblnRightClick Then
'process simulated left click
MsgBox List1.Text
'release right click simulation
mblnRightClick = False
End If
End Sub
Private Sub List1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = vbRightButton Then
'simulate left click
mouse_event MOUSEEVENTF_LEFTDOWN, X, Y, 0, 0
mouse_event MOUSEEVENTF_LEFTUP, X, Y, 0, 0
mblnRightClick = True
End If
End Sub
If you select an item at once, you can put the following code on Menu Popup event:
listBox1.SelectedItem.ToString()
If you want to check all the selected items on listbox (multi select mode), you can use the following code:
Dim k As Long
Dim s As String
For k = 0 To listBox1.ListCount - 1
If listBox1.Selected(k) Then
s = listBox1.List(k)
' ... do something
End If
Next
As the other answers show, the problem is that the listbox doesn't really do what you need. It only changes the selected item on a left click. So you could have the user left clicks on their friend, then right clicks anywhere on the control to warp to that player. BUt that's going to lead to a lot of unexpected arrivals.
You could use coordinates to work out which name had been right clicked, without worrying about it being selected, something like this
Private Sub List_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim IndexRightClicked As Long
If Button = vbRightButton Then
IndexRightClicked = X + Y
WarpMeTo Trim$(List.ItemData(IndexRightClicked))
End If
End Sub
Where X = Y is replaced by maths, knowing the size of items in your list (and correcting for scrolling).
The best option though, I think, is for you to create a user control for the friends list. This will be more work, but means you can create something with the functionality that a good friends list is going to need. Then you could fairly easily use control arrays of CommandButtons or Labels (both can have appearance customized a lot) which are scrolled etc as appropriate.
Related
Ok, after searching for an hour, I still haven't found the right answer for this. All I want is to disable the right click on my button because it's creating a bug, according to our tester. I don't know if VB6 can't do this, but if VB6 can't do this, is there any possible way? Ok, just to be more specific, here is my example...
'I found this somewhere...
Private Sub cmdExportCSV_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = vbRightButton Then
'Do Nothing
End If
End Sub
'Then I have here
Private Sub cmdExportCSV_Click()
'Some logic here
End Sub
But when I click the right button on my mouse, the cmdExportCSV_Click() still executing the code inside.
How about something like this then (based upon your code):
Private m_mouseButton As Integer
Private Sub cmdExportCSV_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
m_mouseButton = Button
End Sub
Private Sub cmdExportCSV_Click()
If m_mouseButton = vbRightButton Then
'Do Nothing
Exit Sub
End If
'Some logic here
End Sub
I didn't run this or anything, but it should work.
I have resolved my own problem.
From this..
Private Sub cmdExportCSV_Click()
If m_mouseButton = vbRightButton Then
'Do Nothing
Exit Sub
End If
'Some logic here
End Sub
To this..
Private Sub cmdExportCSV_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button And vbRightButton Then
Exit Sub
End If
'Some logic here
End Sub
That's it! VB6 won't directly allow you to disable the mouse right and mouse left button. My solution is just to exit event whenever the user click the mouse right button.
Anyway, I'm sorry as I found out that the system is using asImageCommand not CommandButton, so when you declare an event like this "Private Sub cmdExportCSV_Click()", the asImageCommand control will trigger when you click the mouse-right and mouse-left button. But if you are using CommandButton, it will only trigger when you click the left-button, and won't allow you to use the right-button of the mouse.
I think I have to update the title of my question.
I have a VBA UserForm in Excel, with very simple code. It displays a collection (a dictionary, actually) of objects, one at a time, with buttons for "first, previous, next, and last". Everything works great, but if I were to continually click the next button to go through the items, I have to click it slowly (roughly once a second). If I click any faster, the click is ignored. For example, if I click four times over two seconds, it will only 'register' the first and third click and advance twice, instead of four times.
Below is example code for the 'next' button (and the other applicable pieces of code in the userform module):
Private dQIDs As Dictionary
Public Sub TransferQIDs(ByVal dIncomingQIDs As Dictionary)
Set dQIDs = dIncomingQIDs
End Sub
Private Sub bNext_Click()
Call LoadQID(CLng(lIndex.Caption) + 1)
End Sub
Private Sub LoadQID(lQID As Long)
Dim QID As cQID
Set QID = dQIDs(lQID)
lIndex.Caption = lQID
lItems.Caption = "Viewing new QID " & lQID & " of " & dQIDs.Count
Me.tQID = QID.lQID
Me.tTitle = QID.sTitle
Me.tVID = QID.sVendorID
Me.bOS = QID.bOSPatch
Me.bApp = Not QID.bOSPatch
Me.bPrev.Enabled = Not (lQID = 1)
Me.bFirst.Enabled = Not (lQID = 1)
Me.bNext.Enabled = Not (lQID = dQIDs.Count)
Me.bLast.Enabled = Not (lQID = dQIDs.Count)
End Sub
Any ideas?
Personally I would just disable to button while content is loaded.
Private Sub bNext_Click()
Dim b1 As Button
Set b1 = ActiveSheet.Buttons("LoadQID")
REM or Me.LoadQID
b1.Font.ColorIndex = 15
b1.Enabled = False
Application.Cursor = xlWait
Call LoadQID(CLng(lIndex.Caption) + 1)
b1.Enabled = True
b1.Font.ColorIndex = 1
Application.Cursor = xlDefault
End Sub
Reason why this happens is that accessing a single object takes quite a bit of time in Excel. This way if you can click it will be registered.
Alternatively you can toggle UI update with:
Application.ScreenUpdating = False
Application.ScreenUpdating = True
windows is checking for a doubleclick. so if you click fast it registers a doubleclick.
2 options. increase you doubleclick speed in the windows mouse settings
or make a doubleclick event
I've created a program that is fully functional and I have sent it to some clients. Some of them have really old computers with really low resolution and they can't access it easily since the form and the controls are oversized for them. Is there an easy way for me to make it to automatically resize both form and controls according to the resolution?
As I've said in the title, this is for Visual Basic 6.0. Thanks to all of you in advance.
You can store size and location of each control on the form, and move or resize controls according to your needs.
In the code below, I use "TabIndex" property as unique id for each control (I can't remember in my old VB6 memory if that's the right thing to do...).
I store the size of the form, and the size and location of each control in the Form_Load event.
Private lWidth As Long
Private lHeight As Long
Private Enum ePROPERTY
ep_Top = 0
ep_Left = 1
ep_Width = 2
ep_Height = 3
End Enum
Private aControlSize() As Long
Private Sub Form_Load()
Dim ctlTmp As Control
lWidth = Me.Width
lHeight = Me.Height
ReDim aControlSize(3, Form1.Controls.Count)
For Each ctlTmp In Form1.Controls
aControlSize(ctlTmp.TabIndex, ep_Top) = ctlTmp.Top
aControlSize(ctlTmp.TabIndex, ep_Left) = ctlTmp.Left
aControlSize(ctlTmp.TabIndex, ep_Width) = ctlTmp.Width
aControlSize(ctlTmp.TabIndex, ep_Height) = ctlTmp.Height
Next
End Sub
Then each time the form is resized (Form_resize event), you'll have to move or resize each control.
Some of them need to be anchored to the right or to the bottom (or both). Some need to be resized and moved. Others don't need nothing.
Private Sub Form_Resize()
Dim ctlTmp As Control
For Each ctlTmp In Form1.Controls
Select Case LCase$(ctlTmp.Name)
Case "text1"
' Text1 is anchored to the left and right borders of the form :
ctlTmp.Width = Me.Width - (lWidth - aControlSize(ctlTmp.TabIndex, ep_Width))
Case "command1"
' Command1 is anchored to the right border of the form :
ctlTmp.Left = aControlSize(ctlTmp.TabIndex, ep_Left) - (lWidth - Me.Width)
Case "check1"
' check1 is anchored to the bottom border of the form :
ctlTmp.Top = aControlSize(ctlTmp.TabIndex, ep_Top) - (lHeight - Me.Height)
End Select
Next
End Sub
Form loaded :
Form Resized :
Please be advised that my code is largely perfectible...
There's probably a more elegant solution that goes through overload each Control and to add properties/methods like the existing ones in dotnet.
I am making a risk-type game for school that dynamically creates a 4x4 grid of buttons inside a table layout panel in visual basic. I have successfully created the panel and buttons with names that correspond to the row and column of the button. There are also two parallel arrays - one for button owner and the other for button number - that correspond to the owner of the button and the number of "armies" in the button. My issue is that when the user clicks a certain button, I need to reference the button name/value to know how many "armies" the button has to control the "attack" portion of the player's turn.
The following code creates the table layout panel and the buttons with names.
'Create table Dynamically
Dim ColCount As Integer = 4
Dim RowCount As Integer = 4
Dim f As New System.Drawing.Font("Arial", 15)
riskTable.AutoScroll = True
riskTable.Dock = DockStyle.Fill
riskTable.ColumnCount = ColCount
riskTable.RowCount = RowCount
For rowNo As Integer = 0 To riskTable.RowCount - 1
For columnNo As Integer = 0 To riskTable.ColumnCount - 1
Dim buttonname As String
buttonname = "B" & rowNo & columnNo
Dim button As Control = New Button
button.Size = New Size(179, 100)
button.Name = buttonname
button.Text = "1"
button.ForeColor = Color.White
button.Font = f
AddHandler button.Click, AddressOf buttonname_Click
riskTable.Controls.Add(button, columnNo, rowNo)
Next
Next
Me.Controls.Add(riskTable)
This is the dynamic event handler that I created. I tried using 'Me.Click' to get the name of the button, but it only returns the name of the form. I need to have code in here that references the name of the currently clicked button to then in turn reference the box owner and box number arrays.
Private Sub buttonname_Click(sender As Object, e As EventArgs) Handles Me.Click
MessageBox.Show(Me.Name)
End Sub
Any help would be greatly appreciated! I think that once I get this working, the rest of the game will be pretty simple to figure out.
Thanks!
Put the name in 'button.Tag' instead/also:
button.Tag = buttonname
Then it is easy to get the name with:
Private Sub buttonname_Click(sender As Object, e As EventArgs) Handles Me.Click
Dim result As String = CType(CType(sender, System.Windows.Forms.Button).Tag, String)
End Sub
(Check the System.Windows.Forms.Button though, might need some tweak to match your buttons inside the table. riskTable.Controls.button ?)
validation on textbox in vb 6.0
i tried
Private Sub Text1_KeyPress(KeyAscii As Integer)
If Not (KeyAscii = vbKeyBack Or KeyAscii = vbKeyDelete Or KeyAscii = vbKeySpace Or (KeyAscii >= Asc("1") And KeyAscii <= Asc("9"))) Then
KeyAscii = 0
End If
but now i want that paste option should disable when i right click on textbox
If you want to prevent right-click menu items from being used on the textbox you can create your own context menu.
Then, using API calls you need to unhook the default menu from the textbox and hook up the custom menu.
(I'm not aware of other APIs which only let you disable/hide items in the existing context menu)
The downside off course is that any menu item you want to keep such as copy or delete you need to write the code for yourself.
You can find a very good explenation on how to do this here Disable right click menu inside a textbox and here Weird reaction on a popup menu
What next,.. what is if the user uses CTRL+V to paste? Or what if the user has paste mapped to different key combinations, other than CTRL+V?
Validate the data instead?
You can end up writing a lot of code trying to prevent data entry. Why not save that work and instead let the user enter what they like and use the validate event to validate the data?
I wrote a sample on another site on using the validate event of a textbox here: Validate Value Is Numeric. That link also has a vb6 demo project I put together attached in the post.
The type of validation is irrelevant I suppose, it simply demonstrates using the validate event allows you to focus on validating the data, rather than trying to code every single possible way you can think of trying to prevent data to be entered in the first place.
The Validate event is triggered before lostfocus and before the next control's getfocus.
Only if the validate event is not told to cancel the action, will the lostfocus event and any subsequent event be executed.
The Validate event is intended to be used to ensure the control's value is validated before executing any other event.
Private Sub Text1_Change()
If Text1.Tag <> Text1.Text Then
Text1.Text = Text1.Tag
Text1.SelStart = Len(Text1.Text)
End If
End Sub
Private Sub Text1_KeyPress(KeyAscii As Integer)
Text1.Tag = Text1.Text & Chr(KeyAscii)
End Sub
Old problem but still relevant with legacy projects.
The solution proposed by Sam Sylvester is interesting but doesn't allow you to delete characters (use backspace) and appends the 22 ASCII character (Ctrl + V) in the textbox (which is bad).
This solution I found worked for me (prevents paste using Ctrl + V and also using the context menu):
Dim preventPasteFlag As Boolean
Private Sub Text1_Change()
If preventPasteFlag Then
Text1.Text = Text1.Tag
preventPasteFlag = False
Else
Text1.Tag = Text1.Text
End If
End Sub
Private Sub Text1_KeyPress(KeyAscii As Integer)
If KeyAscii = 22 Then
preventPasteFlag = True
End If
End Sub
Private Sub Text1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = 2 Then
preventPasteFlag = True
End If
End Sub
this is quite similar:
Private Sub Text1_Change()
Dim i As Long, sTemp As String
For i = 1 To Len(Text1)
If InStr(1, "0123456789", Mid$(Text1, i, 1)) > 0 Then sTemp = sTemp & Mid$(Text1, i, 1)
Next
Text1 = sTemp
End Sub