On a form I have 4 MSFlexGrids.
The top grid contains dynamic data, which updates once in a while.
The user can enter data in the cells of the 3 other grids.
The data which is used to fill the top grid is received via a Winsock control, processed, and then the results are written into the appropriate cells using .TextMatrix(intRow, intCol) = strData
This works fine. The data is updated flawlessly, and the user can enter his data into the other 3 grids without any problems.
The problem occurs when I want to change the background color of some cells in the top grid.
On rare occasions the received data is very important, and the background color of the corresponding cells should change color.
I change the color of the cells with the following code:
With grd
For lngRow = 1 To .Rows - 1
'default background color
lngBack = vbWhite
'check for important values
If Val(.TextMatrix(lngRow, 1)) >= lngMax Then
'important color
lngBack = &H3040FF
End If
'select whole row
.Row = lngRow
.Col = 0
.RowSel = lngRow
.ColSel = .Cols - 1
'set the background color of the selected row
.CellBackColor = lngBack
Next lngRow
End With 'grd
The problem with this is that when the user is entering data in the other 3 grids, and the background color of a row in the top grid is changed, then the focus moves to the top grid, and the user has to enter his data anew in the grid where he was working.
Is it possible to change the background color of a cell or whole row in a MSFlexGrid without moving the focus to that grid?
So far I could not find a solution to the problem itself.
I created a work around though :
I created an enum containing a value for each grid:
Public Enum ActiveGrid
enuSystem = 0
enuTel = 1
enuRLN = 2
enuRood = 3
enuData = 4
enuCircuit = 5
End Enum
Whenever a grid gets the focus I save the corresponding enum value in a form level variable.
After coloring the required cells in the first grid I return the focus to the grid which last had it.
The user is not editing in the grid itself, but in a textbox which is laid over the cell, so there is no real problem with the grid losing the focus.
When you look closely though you see the focus leave and return quickly.
For now I will accept this work around, and its minor glitches.
Maybe in the future I can come up with a better solution, or anyone else has a better suggestion?
Related
How can I make the below code more efficient, at the moment it takes roughly 30 seconds to complete
The code will clear all cells within a selection which have a white background & then clear all diagonal borders within a selection.
With only the clear cells with white background code it finishes instantly but as soon as I added the remove borders code it became slow.
Sub ADULTClearOnly()
Set sh2 = ThisWorkbook.Worksheets("ADULT Sign On Sheet")
sh2.Select
Cells.Range("B1:F756").Select
For Each Cell In Selection
If Cell.Interior.Color = Excel.XlRgbColor.rgbWhite Then
Cell.Value = ""
End If
Next
Cells.Range("G1:AO757").Select
For Each Cell In Selection
If Cell.Borders(xlDiagonalUp).LineStyle = xlDiagonalUp Then
Cell.Borders(xlDiagonalUp).LineStyle = xlNone
End If
Next
End Sub
There are several issues in your code:
You don't need to, and should not Select to do these actions
Your logic is flawed: xlDiagonalUp is not a LineStyle
Because you are setting any Diagonal Up borders to none, you don't need to iterate the range, do it in one step
So, replace
Cells.Range("G1:AO757").Select
For Each Cell In Selection
If Cell.Borders(xlDiagonalUp).LineStyle = xlDiagonalUp Then
Cell.Borders(xlDiagonalUp).LineStyle = xlNone
End If
Next
with
sh2.Range("G1:AO757").Borders(xlDiagonalUp).LineStyle = xlNone
Similarly,
sh2.Select
Cells.Range("B1:F756").Select
For Each Cell In Selection
If Cell.Interior.Color = Excel.XlRgbColor.rgbWhite Then
Cell.Value = ""
End If
Next
can be reduced to
For Each Cell In sh2.Range("B1:F756")
If Cell.Interior.Color = Excel.XlRgbColor.rgbWhite Then
Cell.ClearContents
End If
Next
I would like to evauluate the value of a textbox report control and hide or display it based on its value, which I can achieve easily with VBA:
If Me.Fixed.Value = 0 Then
Me.Fixed.Visible = False
End If
That works fine, but the query I am using as the report's record source allows a range of records to be printed all at once (1 per page/report), and I want the above code to run for each page/report. I am unsure of where to put the code so that each record will play by the rules. Currently, if I choose a range of 8 records, only the first one does what I want, and as I navigate through the other records in the print preview screen the format of the report is remaining unchanged when it should be changing.
I have tried the following events:
Report:
On Current
On Load
On Got Focus
On Open
On Activate
On Page
Section:
On Format
On Print
On Paint
Where can I put my VBA so that each time I scroll through/navigate the range of records returned on that report my code runs?
You need to set the Visible property back to True as well, otherwise it will remain invisible.
I'm using the Format event of the Details section:
Private Sub Detail_Format(Cancel As Integer, FormatCount As Integer)
If Me.Fixed = 0 Then
Me.Fixed.Visible = False
Else
Me.Fixed.Visible = True
End If
End Sub
This works in Print Preview but not in Report View. There is probably a way to get this to work with the Report View, but I never use this view.
The statement can be simplified:
Me.Fixed.Visible = Not (Me.Fixed = 0)
Note that the Visible property is not available in the Detail_Paint() event, which is the event you need to use to have the conditional formatting apply in Report View. (Which might be required if you are trying to do something fancy such as simulated hyperlinks for a drill-down effect.)
A workaround is to set the ForeColor of the text box to equal the BackColor. Although the text is technically still there, it does not "show" on the displayed report, thus simulating a hidden field.
Private Sub Detail_Paint()
' Check for even numbers
If (txtID Mod 2 = 0) Then
txtID.ForeColor = vbBlack
Else
' Set to back color to simulate hidden or transparent.
' (Assuming we are using a Normal BackStyle)
txtID.ForeColor = txtID.BackColor
End If
End Sub
Example Output:
I'm working with a MSFlexGrid control in VB6, but I'm also having some problems retrieving the ColPos property for merged columns. The grid that I've generated looks something like this:
-----------------------------
| 8/17/2010 |
-----------------------------
| Column 1 | Column 2 |
-----------------------------
The first row is fixed and the two columns are merged, so both columns contain 8/17/2010 in the first row.
During the Click event, I'm positioning a text box over a cell in the second row, and when I set its Left and Top properties using the FlexGrid's ColPos and RowPos properties, I end up with the textbox positioned over column 1. This happens even if I clicked in column 2.
I've checked the Col property, and it's correctly set to 2 after clicking in the second column, but ColPos(1) and ColPos(2) both return the same value, which is the distance from column 1's left edge to the left edge of the control.
When merging is disabled on the flexgrid, the problem goes away, but I'd rather leave it on since it makes the grid a bit more readable.
Is there any way to retrieve the correct position of the selected column when another cell in the column is merged with another one, or do I need to calculate the column position manually?
Haven't found a way to do it through the control, but here's a function that I put together that does the trick. It counts backward from the selected cell until it reaches the leftmost cell it's merged with, and then adds the widths of the merged cells to the first one's position. Probably could be cleaned up some, but this does work.
Private Function RealColPos(Col As Integer, grid as MSFlexGrid)
With grid
Dim i As Integer, merged As Integer
i = Col - 1: merged = 0
Do While .ColPos(Col) = .ColPos(i)
merged = merged + 1
i = i - 1
Loop
If merged > 0 Then
RealColPos = .ColPos(Col - merged)
Do While merged > 0
RealColPos = RealColPos + .ColWidth(Col - merged)
merged = merged - 1
Loop
Else
RealColPos = .ColPos(Col)
End If
End With
End Function
I have a windows application with DataGridView as data presentation. Every 2 minutes, the grid will be refreshed with new data. In order to keep the scroll bar in sync with the new data added, I have to reset its ScrollBars:
dbv.Rows.Clear(); // clear rows
SCrollBars sc = dbv.ScrollBars;
dbv.ScrollBars = ScrollBars.None;
// continue to populate rows such as dbv.Rows.Add(obj);
dbv.ScrollBars = sc; // restore the scroll bar setting back
With above codes, the scroll bar reappears fine after data refresh. The problem is that the application requires to set certain cell as selected after the refresh:
dbv.CurrentCell = dbv[0, selectedRowIndex];
With above code, the cell is selected; however, the scroll bar's position does not reflect the position of the selected cell's row position. When I try to move the scroll bar after the refresh, the grid will jump to the first row.
It seems that the scroll bar position is set back to 0 after the reset. The code to set grid's CurrentCell does not cause the scroll bar to reposition to the correct place. There is no property or method to get or set scroll bar's value in DataGriadView, as far as I know.
I also tried to set the selected row to the top:
dbv.CurrentCell = dbv[0, selectedRowIndex];
dbv.FirstDisplayedScrollingRowIndex = selectedRowIndex;
The row will be set to the top, but the scroll bar's position is still out of sync. Not sure if there is any way to make scroll bar's position in sync with the selected row which is set in code?
I found an answer to resolve issue. As I mentioned that the control does not have methods or properties to set the correct scroll bar value. However, the scroll bar and the DatagridView content will display correct if there is an interaction directly towards to the UI such as touch the scroll bar or grid cell. It looks like that the control needs to be refocused and a repaint.
Simply use the following codes does not cause the scroll bar reset:
dgv.Select();
// or dbv.Focuse();
The way I found is that I have to make the DatagridView control disappear to back again. Fortunately, I have a tab control with several tabs. Then I switch the tab to get scroll bar reset:
int index = myTabCtrl.SelectedIndex;
if (index == (myTabCtrl.TabCount)) {
dgv.SeletecedIndex = 0;
}
else {
dgv.SelectedIndex = index + 1;
}
myTabCtrl.SelectedIndex = index;
If you don't have any way to hide the DatagridView on your form, you could simply minimize the form and then restore it back.
The problem is that there will be a fresh on the UI.
It seems, TAB, SHIFT+TAB, END keys don't always bring last column into the visible view.
The following code inside the CurrentCellChanged event handler seems to fix this issue (vb.net):
If Me.MyDataGridView.CurrentCell IsNot Nothing Then
Dim currentColumnIndex As Integer = e.MyDataGridView.CurrentCell.ColumnIndex
Dim entireRect As Rectangle = _
Me.MyDataGridView.GetColumnDisplayRectangle(currentColumnIndex, False)
Dim visiblePart As Rectangle = _
Me.MyDataGridView.GetColumnDisplayRectangle(currentColumnIndex, True)
If (visiblePart.Width < entireRect.Width) Or (entireRect.Width = 0) Then
Me.MyDataGridView.FirstDisplayedCell = Me.MyDataGridView.CurrentCell
'OR Me.MyDataGridView.FirstDisplayedScrollingColumnIndex = currentColumnIndex
End If
End If
I'm working with some legacy code and need to change the background color of a row (and the font color) in a ListView in VB6 based on some criteria. I need to change the color of the row when the row is selected and not selected. I can change the font color of a non-selected row via the .Foreground property but I can't change the color in any of the other scenarios.
Check out this forum post. Here's an sample from the code which colors every other row:
'\\ loop through the rows to select every other row
For i = 1 To lvwBackColour.ListItems.Count
If (lvwBackColour.ListItems(i).Index Mod 2) = 0 Then
'\\ add a tick to the checkbox
lvwBackColour.ListItems(i).Checked = True
'\\ add the colour to the picturebox
'\\ See Here (http://msdn2.microsoft.com/en-us/library/aa230480(VS.60).aspx)
'\\ for information about the Line method
picBG.Line (0, i - 1)-(1, i), &H4000FF, BF
'\\ update column four caption
lvwBackColour.ListItems(i).SubItems(3) = "Hidden column value = 1"
Else
'\\ remove the tick from the checkbox
lvwBackColour.ListItems(i).Checked = False
'\\ reset backcolour to white
picBG.Line (0, i - 1)-(1, i), &HFFFFFF, BF
'\\ reset the Column Four caption
lvwBackColour.ListItems(i).SubItems(3) = "Hidden column value = 0"
End If
Next i
'\\ set the listview to use the picturebox image
lvwBackColour.Picture = picBG.Image
Here's the link to the msdn article which talks about the Line method.
The background color of selected rows is controlled by the system. You cannot change it to anything else.
If you have to be able to change the background of the selected rows, you will need to custom draw the listview -- which, to be honest, is too much of a pain to seriously consider :)