[Résolu][Calc] Déplacer vers une cellule dans un "viewpane"?

Discussions et questions sur tout ce qui concerne la programmation tous langages et tous modules confondus.

Modérateur: Vilains modOOs

Règles du forum
:alerte: Balisage obligatoire dans cette section !
Aidez-nous à vous aider au mieux en balisant correctement votre question : reportez-vous sur les règles de cette section avant de poster !

[Résolu][Calc] Déplacer vers une cellule dans un "viewpane"?

Messagepar Thierry7777 » 03 Mars 2019 23:40

Bonjour

Voici mon problème: j'ai un document qui contient plusieurs feuilles "splitées" (Affichage->Scinder la fenetre").

Comment faire pour sélectionner un panel ("viewpane") dans une feuille et faire en sorte que les appels (via UNO) se fassent dans ce panel?

Par exemple si la feuille 1 est séparée en deux panels horizontalement et que la feuille active est la feuile 2.
Quand j'éxecute la macro je souhaite positionner la cellule active dans le panel du bas de la feuille 1.

Actuellement, j'ai trouvé comment rendre la feuille 1 active par la méthode:
Code : Tout sélectionner   AgrandirRéduire
ThisComponent.CurrentController.ActiveSheet = thiscomponent.Sheets.getByName("Feuille1")


Ensuite je peux retrouver les infos sur les différents panels grâce aux méthodes:
Code : Tout sélectionner   AgrandirRéduire
controller = ThisComponent.CurrentController
is_split     = controller.getIsWindowSplit()
view_pane_nb = controller.getCount()

view_pane = controller.getByIndex(selected_pane_idx)
first_col = view_pane.getFirstVisibleColumn()
first_row = view_pane.getFirstVisibleRow()
xrange = view_pane.getReferredCells()


Seulement si j'appelle une commande du style :
Code : Tout sélectionner   AgrandirRéduire
document=controller.Frame
args1(0).Name = "ToPoint"
args1(0).Value = "$A$500"
dispatcher.executeDispatch(document, ".uno:GoToCell", "", 0, args1())

ça va sélectionner la cellule dans le panel qui était actif avant l'éxecution de la macro.
Par exemple si la cellule "active" sur la feuille1 était dans le panel supérieur, alors la cellule $A$500 sera affichée dans celui-ci.

Je souhaiterais que le GoToCell s'éxecute systématiquement dans le panel inférieur de la Feuille1.

Sinon, je peux toujours mémoriser les infos sur les différents panels avant l'éxecution des appels puis les restaurer ensuite en fin de macro mais ça fait beaucoup de lignes de code pour quelque chose qui pourrait se résoudre simplement si il était posible d'avoir un "selectViewpane()" au niveau du controller.
Dernière édition par Thierry7777 le 17 Mars 2019 00:18, édité 1 fois.
Libreoffice 6.2.0.3 x64 / Windows 7
Thierry7777
Fraîchement OOthentifié
 
Message(s) : 6
Inscrit le : 02 Mars 2019 22:52

Re: [Calc] Déplacement vers une cellule dans un "viewpane"?

Messagepar Piaf » 04 Mars 2019 19:26

Bonjour
Tu devrais peut-être fixer les lignes plutôt que scinder la fenêtre.
Fixer.gif
Cliquer pour l'animation
Code : Tout sélectionner   AgrandirRéduire
Option Explicit
Sub Main
Dim oDoc as Object, oController as Object, maFeuille as Object, maCellule as Object, oCells as Object
   oDoc = thisComponent
   oController = oDoc.CurrentController
   oController.ActiveSheet = oDoc.Sheets.getByName("Feuille1")
   maFeuille = oController.ActiveSheet   
   oController.freezeAtPosition(0, 17)
   maCellule = maFeuille.getCellRangeByName("D20")
   oController.select(maCellule)
   oCells = oDoc.CreateInstance("com.sun.star.sheet.SheetCellRanges")
   oController.select(oCells)
End Sub
Une solution éventuelle à tester en jouant avec le dispatcher.
Scinder.gif
Cliquer pour l'animation
Code : Tout sélectionner   AgrandirRéduire
Sub Main
Dim oDoc as Object, oController as Object, maFeuille as Object, maCellule as Object, oCells as Object
Dim oFrame as Object, oDispatch as Object
Dim Arg(0) as New com.sun.star.beans.PropertyValue
   oDoc = thisComponent
   oController = oDoc.CurrentController
   oFrame = oController.Frame
   oDispatch = createUnoService("com.sun.star.frame.DispatchHelper")
   'Rendre active le feuille1
   oController.ActiveSheet = oDoc.Sheets.getByName("Feuille1")
   maFeuille = oController.ActiveSheet
   'Récupérer la cellule où la fenêtre est scindée et la définir comme argument
   maCellule = maFeuille.getCellByPosition(oController.getSplitColumn(),oController.getSplitRow()-1)
   Arg(0).Name = "ToPoint"
   Arg(0).Value = split(macellule.AbsoluteName,".")(1)
   'Supprimer le scindage
   oDispatch.executeDispatch(oFrame, ".uno:SplitWindow", "", 0, Array())
   'Aller à la cellule donnée en argument (emplacement à scinder)
   oDispatch.executeDispatch(oFrame, ".uno:GoToCell", "", 0, Arg())
   'Remettre le scindage en place
   oDispatch.executeDispatch(oFrame, ".uno:SplitWindow", "", 0, Array())
   'se rendre à la cellule désirée
   maCellule = maFeuille.getCellRangeByName("D20")
   oController.select(maCellule)
   oCells = oDoc.CreateInstance("com.sun.star.sheet.SheetCellRanges")
   oController.select(oCells)
End Sub
A+
Libre Office Version: 6.1.5 et Apache OpenOffice 4.1.6 Sur Xubuntu 18.04 AMD64
Piaf
GourOOu
GourOOu
 
Message(s) : 5565
Inscrit le : 25 Nov 2011 19:07
Localisation : Guyane

Re: [Calc] Déplacement vers une cellule dans un "viewpane"?

Messagepar Thierry7777 » 16 Mars 2019 23:10

Bonsoir,

Désolé de ne pas avoir répondu plus tôt mais je suis passé à la version 6.2 de LibreOffice et j'ai eu pas mal de soucis avec (notamment des freeze réguliers de l'appli dès que je fais un copier-coller dans l'éditeur de macro).

Finalement, j'ai pu faire une macro qui fonctionne un peu près dans tous les cas. Que la fenêtre soit scindée horizontalement, verticalement ou dans les deux sens.

Je commence par l'initialisation des variables, puis je teste que la fenêtre est bien splittée:
Code : Tout sélectionner   AgrandirRéduire
sub Test_Move_to_cell_in_viewpane
' cell A500
target_cell_col=0
target_cell_row=499

' get access to the document
doc=thiscomponent

' Select feuille1
controller = ThisComponent.CurrentController
sheet = doc.Sheets.getByName("Feuille1")
controller.ActiveSheet = sheet

is_split     = controller.getIsWindowSplit()

Si c'est le cas, je stocke les informations concernant la cellule qui sert de "pivot" et je freeze les viewpane:
Code : Tout sélectionner   AgrandirRéduire
if (is_split = true) then
  ' Check how is split the frame and Fix the viewpanes
  split_pos_h   = controller.getSplitHorizontal()
  split_pos_v   = controller.getSplitVertical()
  split_pos_col = controller.getSplitColumn()
  split_pos_row = controller.getSplitRow()

  ' Fix the panes
  controller.freezeAtPosition(split_pos_col , split_pos_row)
  ' move the active cell in the viewpane
  tmp_cell = sheet.getCellByPosition(split_pos_col, split_pos_row)
  controller.select(tmp_cell)

endif


Ensuite, on peut travailler dans le viewpane resté "actif" (en bas à droite si l'écran est splitté en 4 par exemple)
Code : Tout sélectionner   AgrandirRéduire
' .. Do some work in the sheet ....
' .. Do some work in the sheet ....
     tmp_cell = sheet.getCellByPosition(7, 11)
     controller.select(tmp_cell)
     tmp_cell.String = "X"
' .. Do some work in the sheet ....

Puis pour terminer, je me place dans le viewpane où je souhaite afficher la cellule active,
je defreeze les viewpanes et je mets à jour la cellule active:
Code : Tout sélectionner   AgrandirRéduire
' restore the view panes
if (is_split = true) then

  ' Ensure to be inside the viewpane before to unfreeze
  target_cell = sheet.getCellByPosition(split_pos_col+1, split_pos_row+1)
  controller.select(tmp_cell)

  ' Unfreeze the frame and re-split it
  controller.splitAtPosition(split_pos_h , split_pos_v)

  ' Here you can set the active cell wherever you want
  target_cell = sheet.getCellByPosition(target_cell_col, target_cell_row)
  controller.select(target_cell)

endif

end sub


Quelques petites remarques:
1 - La fonction freezeAtPosition(x,y) utilise des coordonnées en nombre de lignes et de colonnes alors que la fonction splitAtPosition(x,y) utilise des pixels. (cf https://wiki.openoffice.org/wiki/Documentation/DevGuide/Spreadsheets/Spreadsheet_Document_Controller)

2- Il est possible de placer la cellule active dans un autre viewpane en sélectionnant une cellule dans celui-ci avant de les "de-freezés".
Par exemple
Code : Tout sélectionner   AgrandirRéduire
tmp_cell = sheet.getCellByPosition(fsplit_pos_col, split_pos_row-1)
va sélectionner le viewpane du haut (si l'écran est splitté verticalement ou en 4 évidemment).

3- Dans la dernière partie du code, on ne peut pas simplement sélectionner la cellule active avant de de-freezé les viewpanes.
Il faut absolument se placer dans le viewpane, de-freezer puis sélectionner la cellule.
En effet quand les viewpanes sont freezés, il n'est pas possible d'afficher des cellules qui seraient au-dessus ou plus à gauche que la dernière ligne ou dernière colonne des viewpane haut et gauche.
Par exemple dans la feuille ci-dessous (freeze), il n'est pas possible d'afficher les lignes 1 à 8, ni les colonnes A à C dans le viewpane en bas à droite
Example_01.jpg

Alors que si la feuille est simplement splitée, c'est possible:
Example_02.jpg
Example_02.jpg (14.47 Kio) Consulté 32 fois
Libreoffice 6.2.0.3 x64 / Windows 7
Thierry7777
Fraîchement OOthentifié
 
Message(s) : 6
Inscrit le : 02 Mars 2019 22:52

Re: [Résolu][Calc] Déplacer vers une cellule dans un "viewpa

Messagepar Thierry7777 » 17 Mars 2019 20:01

Bon j'ai trouvé également une autre solution au problème.

Comme dans la solution précédente, on commence par initialiser les variables:
Code : Tout sélectionner   AgrandirRéduire
sub Test_Move_to_cell_in_viewpane_2
' cell A500
target_cell_col=0
target_cell_row=499


' get access to the document
doc=thiscomponent

' Select feuille1
controller = ThisComponent.CurrentController
sheet = doc.Sheets.getByName("Feuille2")
controller.ActiveSheet = sheet
frame   = controller.Frame


Puis je teste si la feuille est bien splitée et si c'est le cas, je mémorise les coordonnées de la première cellule affichée dans le viewpane "actif" (i.e. celui qui a le focus dans la feuille):
Code : Tout sélectionner   AgrandirRéduire
is_split     = controller.getIsWindowSplit()

if (is_split = true) then

  first_column = controller.getFirstVisibleColumn()
  first_row = controller.getFirstVisibleRow()

endif


Ensuite on effectue les opérations dans le viewpane "actif"
Code : Tout sélectionner   AgrandirRéduire
' .. Do some work in the sheet ....
     tmp_cell = sheet.getCellByPosition(target_cell_col, target_cell_row)
     controller.select(tmp_cell)
     tmp_cell.String = "Target"
' .. Do some work in the sheet ....
     tmp_cell = sheet.getCellByPosition(7, 200)
     controller.select(tmp_cell)
     tmp_cell.String = "X"
' .. Do some work in the sheet ....


Puis on restaure le viewpane dans l'état où il était au départ:
Code : Tout sélectionner   AgrandirRéduire
' restore the view panes
if (is_split = true) then

  ' Make the target cell active
  target_cell = sheet.getCellByPosition(target_cell_col, target_cell_row)
  controller.select(target_cell)

  ' Restore the current viewpane as it was before to work in it
  controller.setFirstVisibleColumn(first_column)
  controller.setFirstVisibleRow(first_row)


Puis on selectionne le viewpane dans lequel on souhaite afficher la cellule cible.
Ici j'affiche la cellule cible dans la première colonne du viewpane et au milieu verticalement:
Code : Tout sélectionner   AgrandirRéduire
  '
  ' Select the pane where to display the target cell
  '
  'The index container provides the available panes in a specific order, depending on how the view has been split.
  'Index     No split        Vertical split     Horizontal split (*)     Vertical and horizontal split (*)
  '  0     Entire window        Top pane           Left pane                   Top left pane
  '  1         --              Bottom pane         Right pane                 Bottom left pane
  '  2         --                  --                 --                       Top right pane
  '  3         --                  --                 --                      Bottom right pane
  ' (*) If the sheet is in right-to-left layout mode, the panes are swapped too (e.g., pane 0 would be the right pane or the top right pane).

  view_panes_nb= controller.getCount()
 
  if (view_panes_nb = 4) then
    pane = controller.getByIndex(3)
  else
    pane = controller.getByIndex(1)
  endif

  '
  '  Retrieve the visible range of this viewpane
  '
  xrange = pane.getReferredCells()
  range=xrange.getRangeAddress()
  start_col=range.startColumn
  end_col=range.endColumn
  start_row=range.startRow
  end_row=range.endRow
 
  width = end_col - start_col + 1
  height = end_row - start_row + 1
  '
  ' Display the first visible cell of the viewpane
  col_idx = target_cell_col
  row_idx = target_cell_row - (height - 1) / 2
  pane.setFirstVisibleColumn(col_idx)
  pane.setFirstVisibleRow(row_idx)
endif

end sub


Le problème c'est que le focus reste sur le viewpane qui était actif au départ. Il n'est pas transféré au viewpane sélectionné par "pane = controller.getByIndex(x)".
Donc si l'utilisateur appuie sur une flêche de direction, le viewpane actif se déplacera pour afficher la cellule active.
C'est la principale différence avec la solution précédente.

Si quelqu'un sait comment transférer le focus sur un panel donné, merci de poster la solution.
Ca remplacera tout le code ci-dessus.
Libreoffice 6.2.0.3 x64 / Windows 7
Thierry7777
Fraîchement OOthentifié
 
Message(s) : 6
Inscrit le : 02 Mars 2019 22:52


Retour vers Macros et API

Qui est en ligne ?

Utilisateur(s) parcourant ce forum : Aucun utilisateur inscrit et 1 invité