iTextsharp - draw a line at the end and start of a page with tables - vb.net

Selecting records from a table I create iTextsharp's Tables one for every first letter of the records
On the picture a table for the "G" letter:
"G" is a row of 6 cells
Then a row of 6 cells with the "headers"
and then rows with records
The cells of the rows only need left and right border.
But I need to draw or "close" the line for the last row of the page and also draw or "open" the line of the first row of the next page.
I read a lot of post but I can't figure it out the solution
I know how to draw a graphic line and how to find the coords or how to set bottom or top border, but I don´t know how to detect the page break or if I can manage this situation with forced footers or headers only on cases like the one of the picture.
The code of the class adapated to VB
Thanks to COeDev for the support
Now I only need to resolve the Rectangle (or draw a line) because is not the same on VB.NET (Lines marked as comment)
Imports iTextSharp.text.pdf
Public Class LineaBottom
Implements IPdfPTableEvent
Public Sub TableLayout(table As PdfPTable, widths As Single()(), heights() As Single, headerRows As Integer, rowStart As Integer, canvases() As PdfContentByte) Implements IPdfPTableEvent.TableLayout
'Throw New NotImplementedException()
Dim columns As Integer
Dim rect As Rectangle
Dim footer As Integer = widths.Length - table.FooterRows
Dim header As Integer = table.HeaderRows - table.FooterRows + 1
Dim ultima As Integer = footer - 1
If ultima <> -1 Then
columns = widths(ultima).Length - 1
rect = New Rectangle(widths(ultima)(0), heights(ultima), widths(footer - 1)(columns), heights(ultima + 1))
'rect.BorderColor = BaseColor.BLACK
'rect.BorderWidth = 1
'rect.Border = Rectangle.TOP_BORDER
'canvases(PdfPTable.BASECANVAS).Rectangle(rect)
End If
End Sub
I hope this code will serve other people because there is not much information on the Internet

This should be helpful for you: itextsharp: how to show the bottom line of a table with property HeaderRows=1 if border bottom of the row is not set?
You will need to add some code to draw an additional header line, too
e.g.:
columns = widths[0].Length - 1;
rect = new Rectangle(widths[0][0], heights[0], widths[0][columns], heights[0]);
rect.BorderColor = Color.BLACK;
rect.BorderWidth = 1;
rect.Border = Rectangle.TOP_BORDER;
canvases[PdfPTable.BASECANVAS].Rectangle(rect);
4.1.6.0

I found the solution, no new class required
Dim heightActualLetter, verticalSpaceAvailable As Integer
heightActualLetter = table.TotalHeight
verticalSpaceAvailable = pdfWrite.GetVerticalPosition(False) - pdfDoc.BottomMargin
If heightActualLetter > verticalSpaceAvailable Then
Dim finalLine As PdfContentByte
finalLine = pdfWrite.DirectContent
Dim curY As Int32
curY = pdfWrite.GetVerticalPosition(False)
finalLine.SetLineWidth(0.5)
finalLine.MoveTo(xStart, curY)
finalLine.LineTo(xEnd + 1, curY)
finalLine.Stroke()
End If
I don´t know why I need the +1 on xEnd + 1 but maybe is because of the other lines being 0.5 I need to rounded up

Related

Finding width of each line in richtextbox where wordwrap is true

I have a richtextbox and i have put a long sentences. Its wordwrap is on. Because of this it shows 4 lines. I want to show the width of each line separately.
I have tried with richtextbox1.lines.length, but it is showing: 1
I have tested this code briefly and I think that it does what you want. It will include carriage return and line break characters in the count I think, so you will have to handle that explicitly if you need different.
Dim previousFirstCharIndex = 0
Dim lineIndex = 1
Dim firstCharIndex = RichTextBox1.GetFirstCharIndexFromLine(lineIndex)
Dim lineLengths As New List(Of Integer)
Do Until firstCharIndex = -1
lineLengths.Add(firstCharIndex - previousFirstCharIndex)
previousFirstCharIndex = firstCharIndex
lineIndex += 1
firstCharIndex = RichTextBox1.GetFirstCharIndexFromLine(lineIndex)
Loop
lineLengths.Add(RichTextBox1.TextLength - previousFirstCharIndex)
MessageBox.Show(String.Join(Environment.NewLine, lineLengths), "Line Lengths")

How to change Hole Table axis orientation via SolidWorks API?

Is there a way to change orientation (direction) of Hole Table axes with SolidWorks API?
I can do it manually by dragging the handles but recorded VBA macro does not contain actual changes.
This is what I would like to achieve:
Before
After
I don't have Visual Studio Tools on this PC so I cannot record a C# or VB macro and see if it contains more code. If somebody could check that on their PC I would be grateful.
I have figured it out. This time digging through SolidWorks API Help was useful.
By using HoleTable.DatumOrigin.SetAxisPoints() method it is possible to change points that define the Hole Table axes.
Important to notice is that SetAxisPoints() changes only the end points of the axis arrows (tips of the arrowheads). Start points get updated automatically.
You can get current point values with HoleTable.DatumOrigin.GetAxisPoints2() method.
Another thing to notice is that values in the hole table do not get updated automatically. They did update after I manually dragged a an axis point.
To get them update by the code set HoleTable.EnableUpdate property to False before and back to True after the call to SetAxisPoints().
Here is the code excerpt that does what I needed:
Dim ht As SldWorks.HoleTable
Dim htdo As SldWorks.DatumOrigin
Dim htdaxpts() As Double
Dim htdaxptsnew(0 To 3) As Double
Dim ystarty As Double
Dim yendx As Double
Dim yendy As Double
Dim xstartx As Double
Dim xendx As Double
Dim xendy As Double
'...
'here comes code to prepare for Hole Table insertion
'...
'insert the Hole Table
Set htann = theView.InsertHoleTable2(False, anchorx, anchory, swBOMConfigurationAnchor_BottomLeft, "A", holetemplatepath)
If Not htann Is Nothing Then
Set ht = htann.HoleTable
Set htdo = ht.DatumOrigin
'disable hole table update to get it refresh when done
ht.EnableUpdate = False
'get coordinates of the axis arrows (4 pairs of (x,y) doubles: X start(0,1), X end(2,3), Y start(4,5), Y end(6,7))
htdaxpts = htdo.GetAxisPoints2()
'take the values we use
xstartx = htdaxpts(0)
xendx = htdaxpts(2)
xendy = htdaxpts(3)
ystarty = htdaxpts(5)
yendx = htdaxpts(6)
yendy = htdaxpts(7)
'change direction only if Y arrow points up
If ystarty < yendy Then
yendy = ystarty - (yendy - ystarty)
End If
'change direction only if X arrow points left
If xstartx > xendx Then
xendx = xstartx - (xendx - xstartx)
End If
'change position only if X arrow is below Y arrow
If xendy < ystarty Then
'we can change end point only so change X end y only
xendy = xendy + (ystarty - xendy) * 2
End If
'prepare new axis points (2 pairs of (x,y) doubles: X end(0,1), Y end(2,3))
htdaxptsnew(0) = xendx
htdaxptsnew(1) = xendy
htdaxptsnew(2) = yendx
htdaxptsnew(3) = yendy
'set new axis end points
htdo.SetAxisPoints htdaxptsnew
'enable hole table update to refresh the values
ht.EnableUpdate = True
End If

FindAll does not get all Child Objects in WPFListView using SilkTest 17.5

I need to scroll to an element present in table for a WPF application, the value is dynamically provided during run time.
I have below code which runs fine for small listview as scrollbar moves correctly but does not scroll to elements near the end of a long list.
My list is as below and I scroll using names (A1, A2, ...)
A1 1 3
A2 1 5
S1 1 3
Q2 1 5
.....
.....
Z7 1 3
Z82 1 5
Z9 1 3
Imports SilkTest.Ntf.Wpf
Public Module Main
Dim _desktop As Desktop = Agent.Desktop
Public Sub Main()
Dim iPosition As Double = 0.5
Dim iSumPosition As Double = 0.0
Dim sObjlocator As String = "//WPFListView[#automationId='MyListView']"
Dim sData As String = "Z118"
Dim sObjSublocator As String = "//WPFToggleButton[#caption='*']"
Dim rows As IList = _desktop.WPFListView(sObjlocator).FindAll(sObjSublocator)
Dim sObjExist As Boolean = False
For Each row As WPFToggleButton In rows
Dim sString As String = row.Text
Console.WriteLine(sString) ' <--names
If Trim(sString) = sData Then
sObjExist = True
Exit For
Else
iSumPosition += iPosition
Console.WriteLine(iSumPosition) ' <--Position
_desktop.WPFListView(sObjlocator).ScrollToPosition(iSumPosition, Orientation.Vertical)
End If
Next
End Sub
End Module
Issue:
As shown in the output below, the printed lines A1, A10, ... from Console.WriteLine(sString) and the numbers from Console.WriteLine(iSumPosition), works only for a few objects off-screen, the scrollbar moves vertically down, but if my list is large and I need scroll many times then scrolling doesn't work any more.
The scroll bar does not scroll to the end for names near the end of the list, only if my list is very small then it scrolls down to very last element as well.
In Debug mode I see that the rows list (Dim rows As IList = _desktop.WPFListView(sObjlocator).FindAll(sObjSublocator)) does not have the values (names) for elements near the end of the list.
In the output below, we can see names and positions are printed initially but near the end of the long list only positions are printed.
Output:
A1
0.5
A10
1
A11
1.5
A12
2
...
...
...
9.5
10
10.5
Additional info:
Locator type is WPFScrollBar.
WPF pre-fill forms settings in SilkTest is : yes
Using automation testing tool : Microfocus SilkTest 17.5
You could try using a while loop to continually increase the scroll bar value (to scroll down) until the maximum scroll bar value is met. Below I have put together some sample code that demonstrates this when executed against the WPF sample application that ships with Silk Test.
Imports SilkTest.Ntf.Wpf
Public Module Main
Dim _desktop As Desktop = Agent.Desktop
Public Sub Main()
With _desktop.WPFWindow("#caption='WPF Sample Application'")
.SetActive()
.WPFMenu().Select("/Controls/Basic Controls")
End With
With _desktop.WPFWindow("#caption='Basic Controls'")
.WPFTabControl("#automationId='tabControl'").Select("ScrollBar")
Dim sScrollBar As WPFScrollBar
sScrollBar = .WPFScrollBar("//WPFTabControl[#automationId='tabControl']/WPFScrollBar[2]")
'Set the scroll bar to the top
sScrollBar.SetValue(0.0)
System.Threading.Thread.Sleep(1000)
Dim iPosition As Double
iPosition = 0.0
While sScrollBar.Value < sScrollBar.Maximum
Console.WriteLine("scroll Bar Maximum " + sScrollBar.Maximum.ToString)
Console.WriteLine("scroll Bar Value " + sScrollBar.Value.ToString)
'Set Scroll bar position
sScrollBar.SetValue(iPosition)
'Return text within scroll
Console.WriteLine(.WPFTextBox("#automationId='txtScrollBarEvents'").Text)
'Increment scroll bar position for each iteration
iPosition = iPosition + 0.1
System.Threading.Thread.Sleep(1000)
End While
.Close()
End With
End Sub
End Module

How to Implement Rowspan in a GridView (for .NET 3.5)

I created a custom GridView (actually a RadGrid) which does roughly the following.
Initialize GridView formatting
Setup Columns (depending on type of data to be displayed)
Populate the rows
When Instantiating this GridView, and adding it to my page, I want the first column to contain a "rowspan" attribute on the first row of repeated, but similar data. The "rowspan" value should be equal to the number of similar rows following it. In this way I hope to make the final view cleaner.
The logic for this, I figure, should take place while populating the rows. Initially I add rows to a DataTable and then bind it to the GridView as the final step.
Here's the general logic I was attempting, but it didn't work for me. What am I doing wrong?
Dim dt As New DataTable() 'Has three default columns
For Each d In Documents 'MAIN ITEM (First Column Data)
Dim rowspan As Integer
rowspan = 0
For Each f In Files
If rowspan = 0 Then
Me.dt.Rows.Add(New Object() {d.Title, f.Language, f.FileSize})
'THIS DOESN'T WORK!
Me.dt.Columns(0).ExtendedProperties.Item("rowspan") = rowspan.ToString()
Else
Me.dt.Rows.Add(New Object() {Nothing, f.Language, f.FileSize})
End If
rowspan += 1
Next
Next
Also keep in mind that the this is dumped into a DataView which is sorted by the first column, so I would imagine it must actually be sorted first, then somehow count the rows for each "like" first column, then set the "rowspan" value for the first row of that column equal to the number of rows belonging to it.
Does this make sense? Here is an ideal example of what I would like to accomplish in the layout:
Try this.
Protected Sub DemoGrid_PreRender(sender As Object, e As System.EventArgs) Handles DemoGrid.PreRender
MergeRowsWithSameContent(sender)
End Sub
Public Sub MergeRowsWithSameContent(gvw As GridView)
For rowIndex As Integer = gvw.Rows.Count - 2 To 0 Step -1
Dim row As GridViewRow = gvw.Rows(rowIndex)
Dim previousRow As GridViewRow = gvw.Rows(rowIndex + 1)
For i As Integer = 0 To row.Cells.Count - 1
If row.Cells(i).Text = previousRow.Cells(i).Text Then
row.Cells(i).RowSpan = If(previousRow.Cells(i).RowSpan < 2, 2, previousRow.Cells(i).RowSpan + 1)
previousRow.Cells(i).Visible = False
End If
Next
Next
End Sub
P.S: Shameless port of this wonderful code I have been using for years.

How to get the height of a table row in Word

I've looked all over the place and tried various things. It's been assumed that it can't be done. So I'm going to try here and see if anybody else has had any luck.
Is there any way to get the height of a table row in Word when the row's HeightRule is set to wdRowHeightAuto?
Alternatively, if there's a way to get the cell's height instead, I'll accept that as a solution since you can calculate the row's height by finding the row's biggest cell.
It's possible to find the row height with Range.Information(). The following snippet doesn't work for the last row in a table or the last row on a page
Dim Tbl as Table
Dim RowNo as Integer
Dim RowHeight as Double
' set Tbl and RowNo to the table and row number you want to measure
RowHeight=Tbl.Rows(RowNo+1).Range.Information(wdVerticalPositionRelativeToPage) _
- Tbl.Rows(RowNo).Range.Information(wdVerticalPositionRelativeToPage)
This returns the height of the row in points by calculating the difference in position between the selected row and the following one.
I have a routine which works in all cases and returns the height in points of the second and subsequent lines in a cell, i.e. a single-line cell returns 0. (I use this in an application which reduces the font size in certain cells to fit the text on one line.)
Dim Doc As Document
Dim Tbl As Table
Dim Pos As Long
Dim RowNo As Integer
Dim ColNo As Integer
Dim CellHeight As Single
' set Doc, Tbl, RowNo and Colno to the document,table and row number you want to
' measure or provide a cell's range if you prefer
Pos = Tbl.Cell(RowNo, ColNo).Range.End - 1 ' last character in cell
CellHeight = Doc.Range(Pos, Pos).Information(wdVerticalPositionRelativeToTextBoundary)
How about cheating?
Dim tbl As Word.Table
Dim r As Row
Dim c As Cell
Set tbl = ActiveDocument.Tables(1)
For Each r In tbl.Rows
iHeight = r.HeightRule
r.HeightRule = 1
Debug.Print r.Height
r.HeightRule = iHeight
Next
I tried the above and found that changing the HeightRule changes the height of the row, which given I am trying to "freeze" the height on what appears in my table beforehand, makes nonsense of the above.
For rows which are empty or contain a single paragraph of unwrapped text in a consistent paragraph format adding up the font size, para before and after can work as follows:
Set r = c.Row
With r
If .HeightRule <> wdRowHeightExactly Then
.HeightRule = wdRowHeightExactly
Set p = c.Range.ParagraphFormat
.Height = c.BottomPadding + c.TopPadding + p.SpaceBefore + p.SpaceAfter + p.LineSpacing
End If
End With