Ce n'est pas compliqué d'utiliser une vue personnalisée dans Storyboard.
La technique habituelle, que tu connais, c'est de glisser-déposer des composants graphiques de base (NSImageView, NSLabel, NSView, etc.) sur l'écran, et de tirer des IBOutlet vers le code pour les utiliser. La démarche est presque similaire.
Etape 1 : On glisse-déposer sur l'écran un composant graphique " Custom View ".
- On sélectionne la "Custom View " et on affiche l'inspecteur d'identité.
- L'option " Custom Class " permet de définir la classe à associer avec la " Custom View ". Il suffit de cliquer sur l'option " Class " pour voir une (longue) liste de classes possibles. ViewAvecCalque étant créée à partir de NSView, Xcode l'ajoute automatiquement dans la liste.
- Une fois " ViewAvecCalque " sélectionnée, Xcode sait que la " Custom View " appartient à cette classe. En faisant un IBOutlet sur cette vue, il génère automatiquement les bons paramètres.
Ce n'était pas en Swift 3, mais cela m'a pris quelques secondes pour l'adapter (le temps de valider les deux corrections suggérées par Xcode)
extension NSView {
var snapshot: NSImage {
guard let bitmapRep = bitmapImageRepForCachingDisplay(in: bounds) else { return NSImage() }
bitmapRep.size = bounds.size
cacheDisplay(in: bounds, to: bitmapRep)
let image = NSImage(size: bounds.size)
image.addRepresentation(bitmapRep)
return image
}
}
Exemple d'utilisation :
J'ai utilisé Storyboard pour placer sur l'écran, une vue avec calque, une imageView et un détecteur de clic. Quand l'utilisateur clique sur le calque, le programme fait une copie d'écran de son contenu, pour l'afficher dans l'imageView.
Je suis en train de jongler avec le temps, je suis dans le Lot et cà claque pas mal depuis 2 jours avec une pluie d'enfer. C'est vachement rare aussi fort et dans la durée dans le coin. Alors, je branche la box, je la débranche et ainsi de suite, c'est devenu mon quotidien.
Il ne me reste plus que l'enregistrement mais çà je sais faire mais pour tout à l'heure.
Je te rassure, une les images crées je ne reviens plus dessus et si vraiment je dois rajouter un élément, je dois le faire sur toutes les images de mon dossier et là je recommence tout le calcul, c'est hyper rapide. Donc j'efface tout et je recalcule.
C'est bon je l'ai enregistrée, mon code :
// Enregistrement totale de l'image
if let imageDef = imageVue.image?.imagePNGRepresentation() {
let chemin = "/Users/PATRICK/Documents/APP-SAISIE/"
imageDef.write(toFile: "\(chemin)ImageGraph3.png", atomically: false)
}
extension NSView {
var snapshot: NSImage {
guard let bitmapRep = bitmapImageRepForCachingDisplay(in: bounds) else { return NSImage() }
bitmapRep.size = bounds.size
cacheDisplay(in: bounds, to: bitmapRep)
let image = NSImage(size: bounds.size)
image.addRepresentation(bitmapRep)
return image
}
}
Bon çà marche mais j'avoue qu'il y a certaines instruction que je ne comprends pas dans le "snapshot".
Bon çà marche mais j'avoue qu'il y a certaines instruction que je ne comprends pas dans le "snapshot".
Moi non plus, je ne comprend pas tout. J'ai juste recopié un code venant d'internet. Tu peux regarder dans la doc Apple pour comprendre ces instructions. Pour ma part, cela ne m'intéresse pas, c'est trop spécifique à macOS, alors que ma tasse de thé c'est iOS. Il serait temps qu'Apple unifie certaines API. Cocoa est vraiment en retard par rapport à UIKit.
L'exemple d'Apple me parait un brin tiré par les cheveux. Bon d'accord c'est juste un exemple pédagogique pour illustrer l'instruction continue, mais quand même.
let puzzleInput = "great minds think alike"
var puzzleOutput = ""
let charactersToRemove: [Character] = ["a", "e", "i", "o", "u", " "]
for character in puzzleInput {
if charactersToRemove.contains(character) {
continue
} else {
puzzleOutput.append(character)
}
}
print(puzzleOutput)
En plus il ne FONCTIONNE PAS ! Le type qui l'a tapé ne l'a pas testé, ou alors cela correspond à une vieille syntaxe de Swift 1, abandonnée par la suite .. La doc Apple manque souvent de mise à jour, surtout dans les exemples.
// Mauvaise syntaxe (le compilateur hurle à la compilation)
for character in puzzleInput {
}
On ne peut pas énumérer des characters à partir d'un String comme ça. Il faut ajouter l'opérateur d'énumération .characters pour que Xcode comprenne qu'il doit interpréter le String comme un tableau de characters.
// Bonne syntaxe (pour Swift 3.1)
for character in puzzleInput.characters {
}
On peut faire la même chose sans l'instruction continue, pour alléger le code.
let puzzleInput = "great minds think alike"
var puzzleOutput = ""
let charactersToRemove: [Character] = ["a", "e", "i", "o", "u", " "]
for character in puzzleInput.characters {
if !charactersToRemove.contains(character) {
puzzleOutput.append(character)
}
}
print(puzzleOutput)
if textHeure.contains(":") { } else {
continue // suite de la boucle
}
Code pour vérifier que l'heure que j'ai extraite est au format "HH:MM", si true je fais le traitement sinon via "continue" je prends la ligne suivante.
Cà vous parait correct ?
il y a beaucoup de changements dans Swift 4 par rapport à Swift 3 ?
Il existe une autre manière de " sauter " une itération de la boucle for in : le test sur la valeur numérique de l'indice.
La boucle for in ne gère pas l'indice de boucle, en fournissant directement les objets lus. Pour moi c'est l'une des principales innovations du langage, qui n'en manque pas pourtant ! Toujours plus simple, toujours plus lisible, en avant vers l'infini ...
Voici un petit code affichant une liste de noms :
let liste = ["ZERO", "UN", "DEUX", "TROIS", "QUATRE", "CINQ "]
for nom in liste {
print (nom)
}
ZERO
UN
DEUX
TROIS
QUATRE
CINQ
On peut utiliser un opérateur d'énumération pour récupérer l'objet ET son indice :
for (index,nom) in liste.enumerated() {
if index != 3 {
print (nom)
}
}
if textHeure.contains(":") { } else {
continue // suite de la boucle
}
Code pour vérifier que l'heure que j'ai extraite est au format "HH:MM", si true je fais le traitement sinon via "continue" je prends la ligne suivante.
Cà vous parait correct ?
C'est correct, mais c'est un peu bizarre comme manière de l'écrire. Moi j'aurais utilisé l'opérateur de négation (!) pour alléger l'écriture.
if !textHeure.contains(":") {
continue // suite de la boucle
}
Sinon, pour éviter d'aller farfouiller dans l'immensité de la doc Apple et la complexité d'utilisation de CoreText, il reste la bonne vieille solution : afficher les caractères un par un, en calculant leurs positions d'affichage à la " main ".
Cela ne résoudra pas ton problème, ce code effectue une rotation à 90° de l'ensemble du texte. Je doute que tes utilisateurs aient envie de tourner la tête à angle droit pour lire les infos de ton application.
Essaye plutôt ça :
func drawTexteVertical(texte:String,
police:NSFont,
couleur:NSColor,
position:NSPoint) {
var posCourante = position
for char in texte.characters {
let attrStr = NSAttributedString(string: String(char),
attributes: [
NSFontAttributeName : police,
NSForegroundColorAttributeName : couleur])
attrStr.draw(at: posCourante)
posCourante.y -= police.capHeight + 1
}
}
Je viens de taper ce code et de le tester. Exemple en image :
Réponses
Nooonnnnn pitié !
OK, juste pour toi mon petit :
* dans le coma , ne voit rien, n'entend rien *
Draken, tu es sur de çà :
je ne comprend pas
Oui, j'en suis certain. D'autant plus que c'est Storyboard qui a généré cette ligne quand j'ai demandé un IBOulet sur une vue personnalisée.
On peux aussi créer la ViewAvecCalque avec du code, sans passer par Storyboard, à l'ancienne.
Ce n'est pas compliqué d'utiliser une vue personnalisée dans Storyboard.
La technique habituelle, que tu connais, c'est de glisser-déposer des composants graphiques de base (NSImageView, NSLabel, NSView, etc.) sur l'écran, et de tirer des IBOutlet vers le code pour les utiliser. La démarche est presque similaire.
Etape 1 : On glisse-déposer sur l'écran un composant graphique " Custom View ".
Etape 2 :
- On sélectionne la "Custom View " et on affiche l'inspecteur d'identité.
- L'option " Custom Class " permet de définir la classe à associer avec la " Custom View ". Il suffit de cliquer sur l'option " Class " pour voir une (longue) liste de classes possibles. ViewAvecCalque étant créée à partir de NSView, Xcode l'ajoute automatiquement dans la liste.
- Une fois " ViewAvecCalque " sélectionnée, Xcode sait que la " Custom View " appartient à cette classe. En faisant un IBOutlet sur cette vue, il génère automatiquement les bons paramètres.
Merci, hier soir en cherchant un peu sur Web, j'avais trouvé tout ce que tu viens de me présenter.
Cà s'affiche parfaitement, mes lignes se positionnent exactement aux bons endroits, le rêve.
Par contre je voudrais enregistrer cette customView dans un fichier image pour ensuite l'afficher à volonté dans d'autre applis.
Je cherche encore mais si tu as une idée je suis preneur.
Je t'avais donné un lien sur du code permettant de stocker l'image d'une NSView dans une NSImage, non ?
https://pastebin.com/d4puXBi8
Ce n'était pas en Swift 3, mais cela m'a pris quelques secondes pour l'adapter (le temps de valider les deux corrections suggérées par Xcode)
Exemple d'utilisation :
J'ai utilisé Storyboard pour placer sur l'écran, une vue avec calque, une imageView et un détecteur de clic. Quand l'utilisateur clique sur le calque, le programme fait une copie d'écran de son contenu, pour l'afficher dans l'imageView.
À la place d'enregistrer une image, je te conseillerais d'enregistrer les données.
D'abord il faut que tous les types se conforme à NSCoding :
Puis tu peux l'enregistrer en fichier comme :
Ok, la transformation en image marche, cool.
Je suis en train de jongler avec le temps, je suis dans le Lot et cà claque pas mal depuis 2 jours avec une pluie d'enfer. C'est vachement rare aussi fort et dans la durée dans le coin. Alors, je branche la box, je la débranche et ainsi de suite, c'est devenu mon quotidien.
Il ne me reste plus que l'enregistrement mais çà je sais faire mais pour tout à l'heure.
Si tu enregistres une image, qu'est-ce tu fasses lors d'une mise jour des données ?
Je te rassure, une les images crées je ne reviens plus dessus et si vraiment je dois rajouter un élément, je dois le faire sur toutes les images de mon dossier et là je recommence tout le calcul, c'est hyper rapide. Donc j'efface tout et je recalcule.
C'est bon je l'ai enregistrée, mon code :
Bon çà marche mais j'avoue qu'il y a certaines instruction que je ne comprends pas dans le "snapshot".
Donc, après que tu as enregistré les images, tu fait quoi pour les afficher à la place du "ViewAvecCalque" ?
Forcément, c'est plus facile d'enregistrer les données et de "rafraà®chir" la vue lors d'un mise à jour dans le didSet de la var "representedObject" ?
Les données occuperont beaucoup moins d'espace sur le disque et tu pourrait changer "l'image" dans une seule ligne de code :
et dans la vue :
Moi non plus, je ne comprend pas tout. J'ai juste recopié un code venant d'internet. Tu peux regarder dans la doc Apple pour comprendre ces instructions. Pour ma part, cela ne m'intéresse pas, c'est trop spécifique à macOS, alors que ma tasse de thé c'est iOS. Il serait temps qu'Apple unifie certaines API. Cocoa est vraiment en retard par rapport à UIKit.
Quelle flopée d'instruction dans la doc en ligne d'Apple, je m'y perd.
Tiens une autre, dans une boucle "for in" je voudrais sauter ne pas traiter une ligne, comment fait-on pour sauter une ligne dans ce genre de boucle.
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-ID121
Premier paragrapfh et en-dessous la rubrique Control Transfer Statements - comme attendu
Oh Yes, merci
L'exemple d'Apple me parait un brin tiré par les cheveux. Bon d'accord c'est juste un exemple pédagogique pour illustrer l'instruction continue, mais quand même.
En plus il ne FONCTIONNE PAS ! Le type qui l'a tapé ne l'a pas testé, ou alors cela correspond à une vieille syntaxe de Swift 1, abandonnée par la suite .. La doc Apple manque souvent de mise à jour, surtout dans les exemples.
On ne peut pas énumérer des characters à partir d'un String comme ça. Il faut ajouter l'opérateur d'énumération .characters pour que Xcode comprenne qu'il doit interpréter le String comme un tableau de characters.
On peut faire la même chose sans l'instruction continue, pour alléger le code.
Désolée Draken, c'est pas les docs qui ne sont pas à jour, c'est toi ::)
La syntaxe est bien à jour pour Swift 4 8--)
Il faut regarder le haut de la page
Oué, oué * ronchonne *
N'empêche que Patyom bosse avec Swift 3, lui ! Comme tous les dévs en production .. Xcode 4 c'est dans 2 ou 3 mois, pas avant ..
EDIT : Effectivement, ça marche. je viens de tester avec Swift 4 (bêta Xcode 9v3).
Code pour vérifier que l'heure que j'ai extraite est au format "HH:MM", si true je fais le traitement sinon via "continue" je prends la ligne suivante.
Cà vous parait correct ?
il y a beaucoup de changements dans Swift 4 par rapport à Swift 3 ?
Il existe une autre manière de " sauter " une itération de la boucle for in : le test sur la valeur numérique de l'indice.
La boucle for in ne gère pas l'indice de boucle, en fournissant directement les objets lus. Pour moi c'est l'une des principales innovations du langage, qui n'en manque pas pourtant ! Toujours plus simple, toujours plus lisible, en avant vers l'infini ...
Voici un petit code affichant une liste de noms :
On peut utiliser un opérateur d'énumération pour récupérer l'objet ET son indice :
C'est correct, mais c'est un peu bizarre comme manière de l'écrire. Moi j'aurais utilisé l'opérateur de négation (!) pour alléger l'écriture.
Beaucoup moins qu'entre Swift 2 et Swift 3 ! Heureusement d'ailleurs.
Ca y est je me suis lancé sur l'affichage des textes et bien entendu j'ai des questions :
J'ai donc récupéré le code correspondant et là je dois écrire le long de ces lignes VERTICALES, pas facile l'instruction.
"il a toujours quelques chose de compliquer à faire" vous devez vous dire non ?
C'est quelque part là -dedans. Bonne chance :
https://developer.apple.com/library/content/documentation/StringsTextFonts/Conceptual/CoreText_Programming/Introduction/Introduction.html#//apple_ref/doc/uid/TP40005533
Sinon, pour éviter d'aller farfouiller dans l'immensité de la doc Apple et la complexité d'utilisation de CoreText, il reste la bonne vieille solution : afficher les caractères un par un, en calculant leurs positions d'affichage à la " main ".
j'ai trouvé çà :
https://stackoverflow.com/questions/38409634/how-to-rotate-text-in-nsview-mac-os-cocoa-swift
(le code dans la partie basse)
Qu'en pensez-vous, je n'arrive pas à implanter le code dans le prog.
Cela ne résoudra pas ton problème, ce code effectue une rotation à 90° de l'ensemble du texte. Je doute que tes utilisateurs aient envie de tourner la tête à angle droit pour lire les infos de ton application.
Essaye plutôt ça :
Je viens de taper ce code et de le tester. Exemple en image :
mais c'est la rotation à 90° qui m'intéresse