Excel-Kommentare auslesen (und in Array speichern)

  • VB.NET

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von Marcus Gräfe.

    Excel-Kommentare auslesen (und in Array speichern)

    Hallo,

    ich möchte die Zellen und dazugehörenden Kommentare einer Excel-Datei auslesen.
    Mit einem Range-Objekt befülle ich ein Array. Ich erhalte damit die Werte der Zellen.

    Gibt es einen ähnlichen Weg, die Kommentare zu erhalten?


    Hier der Ansatz:

    Imports Excel = Microsoft.Office.Interop.Excel

    Public Class Form1
    Public xl_App As New Microsoft.Office.Interop.Excel.Application
    Private Sub Namen()

    Try
    Dim NachName As String = String.Empty
    Dim VorName As String = String.Empty
    Dim arrNamen(,) As Object '= range.Value(XlRangeValueDataType.xlRangeValueDefault)
    Dim ws As Excel.Worksheet
    Dim rng As Excel.Range

    xl_App.Workbooks.Open("C:\Tabelle1.xlsx")
    ws = xl_App.ActiveWorkbook.Worksheets(1)
    rng = ws.UsedRange
    arrNamen = rng.Value()

    ComboBox1.Items.Clear()
    For n = 1 To arrNamen.GetUpperBound(0)
    If Not arrNamen(n, 1) Is Nothing Then NachName = arrNamen(n, 1)
    If Not arrNamen(n, 2) Is Nothing Then VorName = arrNamen(n, 2)
    ComboBox1.Items.Add(NachName & ", " & VorName)
    Next n
    Catch ex As Exception

    End Try
    End Sub

    Ich könnte natürlich über eine Schleife jeden Kommentar abfragen, etwa so:

    for i =1 to 1000
    If Not wb.Worksheets(j).cells(1, i ).comment Is Nothing Then
    arrKom(1,i)= wb.Worksheets(j).cells(1, i -).comment.text
    next i

    Aber das dauert... :(

    Gibt es eine Möglichkeit, ähnlich wie im ersten Beispiel die Zellen über das Range-Objekt eingelesen, dies auch mit Kommentaren zu tun?
    Oder gibt es da noch andere Ansätze?

    Vielen Dank für jede Anregung!

    Orchov
    Huh?
    Dein Worksheet heisst ws, nicht wahr?

    Du kriegst Deine Auflistung als

    VB.NET-Quellcode

    1. Dim com = ws.Comments

    als Microsoft .Office.Interop .Excel .Comments
    Und dann guckst Du mal, was Dir IntelliSense so alles bietet ...
    Ist zugegebenermaßen etwas versteckt.
    Aber man könnte selbst drauf kommen (Hinweise dazu hast du ja von @us4711 schon bekommen):

    Visual Basic-Quellcode

    1. For Each Comment In ws.Comments
    2. Debug.Print (Comment.Shape.OLEFormat.Object.Text)
    3. Next
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Zunächst, vielen Dank, es funktioniert!

    Aber das Auslesen der Kommentare an und für sich hatte ich ja schon über die For-Next Schleife realisiert.
    Gut, es wird jede Celle abgefragt, könnte vielleicht länger dauern.
    Andererseits ist meine Tabelle etwa so aufgebaut: Spalte A: Vorname, meist mit Kommentar; Spalte B Nachname, meist mit Kommentar; Spalte C Strasse usw.
    Es interessieren mich jetzt aber nur die Kommentare aus Spalte A und B.

    Mit einer For/ Each Schleife sehe ich den Vorteil, dass nur vorhandene Kommentare ausgelesen werden.
    Andererseits geht der Vorteil dadurch wieder verloren, dass Kommentare aus den uninteressanten Spalten geholt werden.

    Mein Problem ist nicht, grundsätzlich an die Kommentare zu kommen, sondern die Geschwindigkeit.
    Deswegen lese ich ja auch die Zellen-Inhalte nicht mit einer Schleife aus, sondern definiere ein Range-Objekt, lade den Bereich in ein Array, und das Array wird dann mit einem Workaround ausgewertet/verwurstet (->Füllen der ComboBox, siehe oben)
    Diese Methoden bietet erhebliche Geschwindigkeitsvorteile.
    Leider kann ich nicht auf diese Art und Weise auf die Kommentare kommen. Ich möchte gerne vermeiden, hunderte oder mehr Zeilen einzeln ansprechen zu müssen.

    Hiermit bekomme ich zumindest alle Kommentare zwischengespeichert:

    Dim ws As Microsoft.Office.Interop.Excel.Worksheet
    Dim xl_Comments As Microsoft.Office.Interop.Excel.Comments
    ws = xl_App.ActiveWorkbook.Worksheets(1)
    xl_Comments = ws.Comments
    Dim Kom As String = xl_Comments.ToString

    Aber leider schaffe ich es auch hier nicht, die Kommentare auf die beiden Spalten zu begrenzen.
    Problem ist offenbar, dass auf Kommentare nicht über das Range-Objekt zugegriffen werden kann.

    Oder liege ich falsch?

    Vielen Dank an jeden, der versucht, sich in die Problematik "hereinzudenken"!

    orchov schrieb:

    Problem ist offenbar, dass auf Kommentare nicht über das Range-Objekt zugegriffen werden kann.
    Auch ein Cell-Objekt ist vom Typ Range.
    Ich möchte gerne vermeiden, hunderte oder mehr Zeilen einzeln ansprechen zu müssen.
    Ich möchte behaupten, dass du bei einigen tausend Zellen noch keinen spürbaren Performance-Einbruch hast.

    orchov schrieb:

    leider schaffe ich es auch hier nicht, die Kommentare auf die beiden Spalten zu begrenzen.
    Du musst halt abfragen, ob die Kommentarzelle in deinem beobachteten Range liegt:

    VB.NET-Quellcode

    1. WatchRange = ws.Range("A:A,C:C") 'oder eben ws.Range("A:B")
    2. For Each Comment In Comments
    3. If Not xlApp.Intersect(WatchRange , Comment.Parent) Is Nothing Then Debug.Print (Comment.Parent.Address & " -- " & Comment.Shape.OLEFormat.Object.Text)
    4. Next
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Vielmals sorry (wenn ich widerspreche),

    ich befülle ein Listview mit den Daten aus Zellen, und werte (im Moment) etwa 2x200 Zellen aus. Das befüllen einer Combobox dauert an unterschiedlichen Rechner 5-8 Sek.
    Ich finde das schon etwas langsam.
    Mit der Methode, die ich oben beschrieben habe, komme ich auf 1, vielleicht 2 Sek.

    Auf jeden Fall vielen Dank für Dein Beispiel.
    Als ich es gelesen habe, habe ich mir gedacht, ja, das "isset"!
    Aber (Nochmals sorry, diesmal für meine Unwissenheit), von welchem Typ soll den WatchRange sein???

    Ich dachte, es sollte Range sein, bekomme aber nur Laufzeitfehler, habe mal verschiedenes ausprobiert, aber funzt nicht:

    Dim Comment As Microsoft.Office.Interop.Excel.Comment
    Dim ws As Microsoft.Office.Interop.Excel.Worksheet
    Dim xl_Comments As Microsoft.Office.Interop.Excel.Comments

    xlApp.Workbooks.Open("C:\Test\Mappe1.xlsx")
    ws = xlApp.ActiveWorkbook.Worksheets(1)
    xl_Comments = ws.Comments

    Dim WatchRange As Microsoft.Office.Interop.Excel.Range ' ->Fehler HRESULT: 0x800A03EC
    'Dim WatchRange ->Fehler
    'Dim WatchRange As Object -> Fehler
    WatchRange = ws.Range("A:A,B:B") 'oder eben ws.Range("A:B") -> Fehler

    For Each Comment In xl_Comments
    'If Not xlApp.Intersect(ws.Range("A:A,B:B"), Comment.Parent) Is Nothing Then Debug.Print(Comment.Parent.Address & " -- " & Comment.Shape.OLEFormat.Object.Text) ' -> Fehler
    If Not xlApp.Intersect(WatchRange, Comment.Parent) Is Nothing Then Debug.Print(Comment.Parent.Address & " -- " & Comment.Shape.OLEFormat.Object.Text) ' ->Fehler
    Next


    Verwirrenderweise funktioniert der adaptierte Code in Excel selbst ja:

    Sub comment()

    Dim ws As Worksheet
    Dim xlCom As Excel.comment
    Dim rng As Range
    Set ws = ThisWorkbook.Worksheets(1)

    For Each xlCom In ws.Comments 'ws.Comments
    If Not Intersect(Range(ws.Cells(1, "A"), ws.Cells(5, "A")), xlCom.Parent) Is Nothing Then
    Debug.Print (xlCom.Parent.Address & " -- " & xlCom.Shape.OLEFormat.Object.Text)
    End If
    Next

    End Sub

    Warum wird der Code in VB nicht verarbeitet?

    Edit:Fehler gefunden, die Definition für den Range-Bereich war fehlerhaft.
    So geht's:
    Dim WatchRange As Microsoft.Office.Interop.Excel.Range
    WatchRange = ws.Range(ws.Cells(1, "A"), ws.Cells(5, "A"))
    For Each Comment In xl_Comments
    If Not xlApp.Intersect(WatchRange, Comment.Parent) Is Nothing Then Debug.Print(Comment.Parent.Address & " -- " & Comment.Shape.OLEFormat.Object.Text)
    Next

    Vielen Dank an Euch!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „orchov“ ()

    Das hat mir sehr geholfen:

    petaod schrieb:


    Visual Basic-Quellcode

    1. For Each Comment In ws.Comments
    2. Debug.Print (Comment.Shape.OLEFormat.Object.Text)
    3. Next


    Visual Basic-Quellcode

    1. Sub KommentareInNeuesBlattSchreiben()
    2. Dim wksMitKommentaren As Worksheet 'die Tabelle mit Kommentaren
    3. Dim wksAusdruck As Worksheet 'die Tabelle zum Ausdrucken
    4. Dim cmtDieser As Comment 'ein Kommentar
    5. Dim lngZeile As Long
    6. Dim WatchRange As Range
    7. Set wksMitKommentaren = ActiveSheet 'Achtung, vorher merken, weil neues Blatt kommt
    8. Set wksAusdruck = ThisWorkbook.Worksheets.Add() 'macht eine neue Tabelle
    9. ActiveSheet.Name = "Kommentare_Spalte_C" 'Tabellenname passend zur Spalte ändern
    10. Set WatchRange = wksMitKommentaren.Range("C:C") 'nacheinander Tabellenspalte ändern
    11. With wksAusdruck
    12. 'Titelzeile schreiben:
    13. lngZeile = 1
    14. .Cells(lngZeile, 1).Value = "Adresse1" 'vor jeden führenden Punkt wird wksAusdruck gesetzt wegen "With"
    15. .Cells(lngZeile, 2).Value = "Adresse2"
    16. .Cells(lngZeile, 3).Value = "Zellwert"
    17. .Cells(lngZeile, 4).Value = "Kommentar"
    18. .Cells(lngZeile, 5).Value = "Transparenz"
    19. .Rows(lngZeile).Font.Bold = True 'Titelzeile fett machen
    20. For Each cmtDieser In wksMitKommentaren.Comments
    21. If Not Intersect(cmtDieser.Parent, WatchRange) Is Nothing Then
    22. ' lngZeile = lngZeile + 1
    23. ' .Cells(lngZeile, 1).Value = "A" & lngZeile
    24. ' .Cells(lngZeile, 2).Value = cmtDieser.Parent.AddressLocal
    25. ' .Cells(lngZeile, 3).Value = cmtDieser.Parent.Value
    26. ' .Cells(lngZeile, 4).Value = cmtDieser.Text
    27. ' .Cells(lngZeile, 5).Value = cmtDieser.Shape.Fill.Transparency
    28. Debug.Print (cmtDieser.Shape.OLEFormat.Object.Text)
    29. End If
    30. Next
    31. End With
    32. End Sub


    petaod schrieb:


    Du musst halt abfragen, ob die Kommentarzelle in deinem beobachteten Range liegt:

    VB.NET-Quellcode

    1. WatchRange = ws.Range("A:A,C:C") 'oder eben ws.Range("A:B")
    2. For Each Comment In Comments
    3. If Not xlApp.Intersect(WatchRange , Comment.Parent) Is Nothing Then Debug.Print (Comment.Parent.Address & " -- " & Comment.Shape.OLEFormat.Object.Text)
    4. Next


    Mit nachfolgendem Code lassen sich die Kommentare zu jeder einzelnen Spalte der Tabelle mit Kommentaren auf jeweils ein neues Tabellenblatt "Kommentare_Spalte_C" usw. schreiben:

    Tabellenname und Spalte sind vor der Ausführung des Makros entsprechend anzupassen.

    Visual Basic-Quellcode

    1. Sub KommentareInNeuesBlattSchreiben()
    2. Dim wksMitKommentaren As Worksheet 'die Tabelle mit Kommentaren
    3. Dim wksAusdruck As Worksheet 'die Tabelle zum Ausdrucken
    4. Dim cmtDieser As Comment 'ein Kommentar
    5. Dim lngZeile As Long
    6. Dim WatchRange As Range
    7. Set wksMitKommentaren = ActiveSheet 'Achtung, vorher merken, weil neues Blatt kommt
    8. Set wksAusdruck = ThisWorkbook.Worksheets.Add() 'macht eine neue Tabelle
    9. ActiveSheet.Name = "Kommentare_Spalte_C" 'Tabellenname passend zur Spalte ändern
    10. Set WatchRange = wksMitKommentaren.Range("C:C") 'nacheinander Tabellenspalte ändern
    11. With wksAusdruck
    12. 'Titelzeile schreiben:
    13. lngZeile = 1
    14. .Cells(lngZeile, 1).Value = "Adresse1" 'vor jeden führenden Punkt wird wksAusdruck gesetzt wegen "With"
    15. .Cells(lngZeile, 2).Value = "Adresse2"
    16. .Cells(lngZeile, 3).Value = "Zellwert"
    17. .Cells(lngZeile, 4).Value = "Kommentar"
    18. .Cells(lngZeile, 5).Value = "Transparenz"
    19. .Rows(lngZeile).Font.Bold = True 'Titelzeile fett machen
    20. For Each cmtDieser In wksMitKommentaren.Comments
    21. If Not Intersect(cmtDieser.Parent, WatchRange) Is Nothing Then
    22. lngZeile = lngZeile + 1
    23. .Cells(lngZeile, 1).Value = "A" & lngZeile
    24. .Cells(lngZeile, 2).Value = cmtDieser.Parent.AddressLocal
    25. .Cells(lngZeile, 3).Value = cmtDieser.Parent.Value
    26. .Cells(lngZeile, 4).Value = cmtDieser.Text
    27. .Cells(lngZeile, 5).Value = cmtDieser.Shape.Fill.Transparency
    28. End If
    29. Next
    30. End With
    31. End Sub


    Mit nachfolgendem Code lassen sich die Hyperlinks in die Tabelle mit den Kommentaren schreiben:

    In der Tabelle mit den Kommentaren ist manuell jeweils eine leere Spalte für die Hyperlinks einzufügen, weil beim Einfügen der Hyperlinks der Zelleninhalt überschrieben wird. Die Adresse2 in der Tabelle "Kommentare_Spalte_C" usw. ist vor der Ausführung des Makros entsprechend anzupassen.

    Visual Basic-Quellcode

    1. Sub HyperlinkaufandereTabelleeinfügen()
    2. 'Tabellenname passend zu Spalte ändern
    3. Dim lngZeile As Long
    4. With Worksheets("Kommentare_Spalte_C")
    5. For lngZeile = 2 To .Cells(Rows.Count, 1).End(xlUp).Row
    6. Range(CStr(Sheets("Kommentare_Spalte_C").Cells(lngZeile, 2))).Select
    7. ActiveSheet.Hyperlinks.Add Anchor:=Selection, Address:="", SubAddress:="" & "Kommentare_Spalte_C!" & CStr(Sheets("Kommentare_Spalte_C").Cells(lngZeile, 1)) _
    8. , TextToDisplay:=CStr(Sheets("Kommentare_Spalte_C").Cells(lngZeile, 1))
    9. Next
    10. End With
    11. End Sub

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „blgUcjnl“ ()

    @blgUcjnl
    Der Thread ist fast 7 Jahre alt und der Threadersteller nicht mehr registriert. Noch dazu sieht mir dein Code eher nach VB 6 oder sogar VBA aus, hier geht's aber um .NET. Bitte beim nächsten Mal drauf achten!

    Topic geschlossen.
    Besucht auch mein anderes Forum:
    Das Amateurfilm-Forum